Skip to main content

Architecture

Overview​

This project implements a Copr-like RPM build and hosting system using:

  • GitHub Actions: CI/CD pipeline for building RPMs
  • Mock: Isolated chroot environments for building
  • Cloudflare R2: Storage for RPMs and metadata
  • GPG: Package signing for security

System Components​

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ GitHub Actions β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ build-x86_64 β”‚ β”‚ build-aarch64 β”‚ β”‚ build (main job) β”‚ β”‚
β”‚ β”‚ ubuntu-latest β”‚ β”‚ ubuntu-latest- β”‚ β”‚ - Checkout β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ arm64 β”‚ β”‚ - Build container β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Import GPG β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Configure R2 β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Build RPMs β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Sign RPMs β”‚ β”‚
β”‚ β”‚ β”‚ β”‚ β”‚ β”‚ - Upload to R2 β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Mock Container β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ Isolated chroot environments per target β”‚ β”‚
β”‚ β”‚ - fedora-43-x86_64 β”‚ β”‚
β”‚ β”‚ - almalinux-10-x86_64 β”‚ β”‚
β”‚ β”‚ - centos-stream-10-x86_64 β”‚ β”‚
β”‚ β”‚ - (ARM64 targets) β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Cloudflare R2 β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ /repo/ β”‚ β”‚ /sources/ β”‚ β”‚ /public.gpg β”‚ β”‚
β”‚ β”‚ β”œβ”€β”€ fedora-43/ β”‚ β”‚ β”œβ”€β”€ glib/ β”‚ β”‚ (GPG public key) β”‚ β”‚
β”‚ β”‚ β”œβ”€β”€ almalinux/ β”‚ β”‚ β”œβ”€β”€ gtk4/ β”‚ β”‚ β”‚ β”‚
β”‚ β”‚ └── centos/ β”‚ β”‚ └── ... β”‚ β”‚ β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
β”‚
β–Ό (Optional)
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Cloudflare Worker β”‚
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β” β”‚
β”‚ β”‚ - Custom domain routing β”‚ β”‚
β”‚ β”‚ - dnf/yum metadata handling β”‚ β”‚
β”‚ β”‚ - Security headers β”‚ β”‚
β”‚ β”‚ - Request logging β”‚ β”‚
β”‚ β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜ β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Build Pipeline​

1. Trigger​

  • Push to main branch
  • New tag (v*)
  • dispatch

Manual workflow### 2. Container Build

FROM fedora:43

# Install build tools
RUN dnf install -y mock createrepo_c rpm-sign rpm-build ...

3. Chroot Initialization​

Mock creates isolated environments:

  • Downloads base packages
  • Configures repos
  • Sets up build user

4. SRPM Build​

rpmbuild -bs my-package.spec  # Creates .src.rpm

5. RPM Build​

mock -r fedora-43-x86_64 --srpm my-package.src.rpm
mock -r fedora-43-x86_64 --build my-package.src.rpm

6. Signing​

rpmsign --addsign *.rpm

7. Upload​

aws s3 sync output/ s3://bucket/repo/
createrepo_c --update .

Storage Layout​

r2://repo-james-rc/
β”œβ”€β”€ public.gpg # GPG public key
β”œβ”€β”€ repo/
β”‚ β”œβ”€β”€ fedora-43-x86_64/
β”‚ β”‚ β”œβ”€β”€ my-package-1.0.0-1.fc43.x86_64.rpm
β”‚ β”‚ └── repodata/
β”‚ β”‚ β”œβ”€β”€ repomd.xml
β”‚ β”‚ β”œβ”€β”€ primary.xml.gz
β”‚ β”‚ └── ...
β”‚ β”œβ”€β”€ almalinux-10-x86_64/
β”‚ β”œβ”€β”€ almalinux-10-x86_64_v2/
β”‚ β”œβ”€β”€ almalinux-10-aarch64/
β”‚ β”œβ”€β”€ centos-stream-10-x86_64/
β”‚ └── centos-stream-10-aarch64/
└── sources/ # Lookaside cache
β”œβ”€β”€ glib/
β”‚ └── glib-2.80.0.tar.xz
└── ...

Security​

GPG Signing​

  • Dedicated subkey for RPM signing
  • Private key stored in GitHub Secrets
  • Imported at build time
  • All RPMs signed before upload

Network Access​

  • R2 accessed via AWS CLI with scoped credentials
  • Worker can add IP allowlisting
  • CDN provides DDoS protection

Retention Policy​

The cleanup script (scripts/cleanup.py):

  • Runs after each build
  • Keeps latest 3 versions of each package
  • Saves storage costs
  • Configurable via --keep flag

Multi-Architecture​

x86_64 Builds​

  • Standard runners: ubuntu-latest
  • Native execution

ARM64 Builds​

  • Free runners: ubuntu-latest-arm64
  • Native execution on ARM
  • Pre-installed QEMU in container for compatibility

x86_64_v2​

  • Builds with SSE4.2/AVX2 optimizations
  • Compatible with modern x86_64 CPUs
  • Falls back gracefully on older CPUs

Local Development​

Using justfile​

# Build single target
just build fedora-43-x86_64

# Build all x86_64
just build-x86_64

# Build all targets
just build-all

# Publish to R2
just publish fedora-43-x86_64

Using Container Script​

./scripts/build-local.sh <package> <target>

Dependencies​

Runtime​

  • mock: Chroot package builder
  • createrepo_c: Repository metadata generator
  • rpm-sign: RPM signing tool

Build​

  • rpm-build: RPM building tools
  • Distribution-specific mock configs

Storage​

  • Cloudflare R2
  • AWS CLI for S3 operations