| 1 |
1 |
|
# Image composition
|
| 2 |
2 |
|
|
| 3 |
|
- |
How Alloy is built and delivered. bootc + Containerfile, source on `git.sr.ht`, CI on `builds.sr.ht`, container image on `quay.io`. Companion to [STACK.md](STACK.md).
|
|
3 |
+ |
How Alloy is built and delivered. bootc + Containerfile, source on `makenot.work`, built locally and natively, container image on `quay.io` when distribution starts. Companion to [STACK.md](STACK.md).
|
| 4 |
4 |
|
|
| 5 |
5 |
|
## Landscape
|
| 6 |
6 |
|
|
| 38 |
38 |
|
|
| 39 |
39 |
|
## Delivery stack
|
| 40 |
40 |
|
|
| 41 |
|
- |
### Source: `git.sr.ht/~maxmj/alloy`
|
|
41 |
+ |
### Source: `makenot.work/git/max/alloy`
|
| 42 |
42 |
|
|
| 43 |
|
- |
Primary remote. Alloy is source-hosted on sr.ht for the same reasons the rest of Make Creative's public work is: independence from big-tech-monopoly infrastructure at the layer where users install software. `srht` is a canonical remote for Alloy, not a backup.
|
|
43 |
+ |
Alloy publishes its source on Make Creative's own platform, for the reason the project holds elsewhere: independence from big-tech-monopoly infrastructure at the layer where users install software, and hosting our own source rather than renting someone's. `astra` is the private mirror and `srht` is a backup remote, not the public face. See `~/Code/CLAUDE.md`, "What each remote is for".
|
| 44 |
44 |
|
|
| 45 |
|
- |
### CI: `builds.sr.ht` (disabled during local-iteration phase)
|
|
45 |
+ |
**Current state:** the `mnw` remote is configured but not pushed, so that URL is not live yet. Alloy goes public when there is a manual for a stranger to read.
|
| 46 |
46 |
|
|
| 47 |
|
- |
sr.ht ships Fedora build VMs with `dnf`, `podman`, `buildah`, `skopeo` preinstalled. When ready, the build file at `.builds/alloy-image.yml` triggers on every push.
|
|
47 |
+ |
### CI: none. Builds are local and native.
|
| 48 |
48 |
|
|
| 49 |
|
- |
**Current state:** the build file lives at `builds.disabled/alloy-image.yml`, parked outside the `.builds/` path sr.ht auto-runs, so no CI resources are consumed while the Containerfile is being iterated locally. Rename the directory back to `.builds/` and push to re-enable.
|
|
49 |
+ |
Alloy has no hosted CI, and the sourcehut build that used to stand in for one is gone (`builds.disabled/alloy-image.yml`, deleted; it had been parked outside `.builds/` since `8d0bca6` and pinned `image: fedora/41`, two releases behind the base).
|
|
50 |
+ |
|
|
51 |
+ |
The image is built by `build/build-image.sh` (disk images, via bootc-image-builder) and `build/build-iso.sh` (the installer ISO) on fw13, against rootful podman. That is the whole build story today, and it is a deliberate consequence of two standing rules rather than an accident: builds are native per architecture and nothing is cross-compiled, and app binaries are never built on the production host.
|
|
52 |
+ |
|
|
53 |
+ |
Which means an always-on x86_64 builder is the actual missing piece, not a CI config. astra is always-on but aarch64, and the image is x86_64. fw13 is x86_64 but sleeps aggressively. Until one machine is both, "CI" would be a scheduler with nothing to schedule onto. The Fedora build host meant to replace Pop!_OS on fw13 is where this resolves.
|
| 50 |
54 |
|
|
| 51 |
55 |
|
### Registry: `quay.io` (deferred until distribution starts)
|
| 52 |
56 |
|
|
| 53 |
57 |
|
Red Hat's container registry is the intended destination once Alloy has an image worth distributing. Free for public images, ecosystem-coherent with the `quay.io/fedora/fedora-bootc:43` base.
|
| 54 |
58 |
|
|
| 55 |
|
- |
**Current state:** no registry provisioned. `.builds/alloy-image.yml` runs a **build + lint smoke test** only, validating the Containerfile on every push, without publishing anywhere. When the image is worth distributing, the CI file grows back `sign` and `push` tasks and `quay.io/alloy/alloy` gets provisioned with a robot account.
|
|
59 |
+ |
**Current state:** no registry provisioned, and nothing validates the Containerfile except running `build/build-image.sh` by hand. The old sourcehut job did a build-and-lint smoke test on every push; deleting it means that check now happens when someone remembers to build, which is worth naming rather than glossing. When the image is worth distributing, `quay.io/alloy/alloy` gets provisioned with a robot account and whatever builder exists by then grows `sign` and `push` steps.
|
| 56 |
60 |
|
|
| 57 |
61 |
|
Rejected alternatives (for when distribution starts): ghcr.io (source-registry ecosystem mismatch), Docker Hub (pull rate limits, no advantage), self-hosted (real infra commitment, not worth v0 operational load; revisit v2+).
|
| 58 |
62 |
|
|
| 59 |
63 |
|
### Signing: cosign (deferred alongside distribution)
|
| 60 |
64 |
|
|
| 61 |
|
- |
Once a registry is publishing images, cosign signs them as a CI task. Private key stored as an sr.ht secret; public key published in the Alloy repo. Users verify via `bootc switch --signature-source=<url>`. Nothing to set up until distribution starts.
|
|
65 |
+ |
Once a registry is publishing images, cosign signs them as a build step. Public key published in the Alloy repo. Users verify via `bootc switch --signature-source=<url>`. Nothing to set up until distribution starts.
|
|
66 |
+ |
|
|
67 |
+ |
The private key needs a home, and "an sr.ht secret" was the old answer, which went out with the sourcehut build. Whatever builds and pushes the image is what needs to hold it; a signing key on a machine that sleeps is a different problem from a signing key in a hosted secret store, and that is another thing the builder decision settles.
|
| 62 |
68 |
|
|
| 63 |
69 |
|
## Layer structure
|
| 64 |
70 |
|
|
| 77 |
83 |
|
|
| 78 |
84 |
|
## Update cadence
|
| 79 |
85 |
|
|
| 80 |
|
- |
The sr.ht build triggers on:
|
|
86 |
+ |
There is no automated trigger today. The image is rebuilt when someone runs `build/build-image.sh`.
|
| 81 |
87 |
|
|
| 82 |
|
- |
- **Push to `main`**: Alloy commits.
|
| 83 |
|
- |
- **Weekly cron**: picks up upstream Fedora base image updates. sr.ht doesn't have webhook receivers for external triggers, so cron is the pragmatic answer.
|
|
88 |
+ |
Two triggers are wanted whenever a builder exists, and they are worth writing down now because the second is the one a manual process silently drops:
|
|
89 |
+ |
|
|
90 |
+ |
- **On a commit to `main`**, so a Containerfile that no longer builds is caught by the person who broke it.
|
|
91 |
+ |
- **Weekly**, to pick up upstream Fedora base updates. Nothing in Alloy changes, and the image still does: this is the trigger a human never remembers, and its absence means the base drifts until the next hand build notices.
|
| 84 |
92 |
|
|
| 85 |
93 |
|
Users receive updates via `bootc upgrade`: no push notifications, no forced restart. Alloy's update UX is the standard bootc UX.
|
| 86 |
94 |
|
|
| 95 |
103 |
|
- [ ] Verify which Alloy packages are in Fedora main vs. need COPRs. Candidates that may need COPRs: `satty`, `wl-screenrec` (depending on Fedora version). Audit at v0 packaging time.
|
| 96 |
104 |
|
- [ ] `bootc-image-builder` for ISO generation. First-time-user path is `bootc install` from a live environment; the ISO is what makes that a smooth experience. Verify the ISO builder handles Alloy's specific package set.
|
| 97 |
105 |
|
- [x] **Containerfile stage policy: multi-stage only where a non-Fedora Rust binary needs to ship.** Currently that is one stage, `rust-build`, and it builds the Alloy console. Everything else comes from RPM in the runtime stage. Do not add stages preemptively. Corrected 2026-07-19: this line named wl-screenrec as the stage's occupant, which was stale — wl-screenrec was deferred rather than shipped, so for a while there was no stage at all. The console is the case the policy was written for and did not anticipate: it is the one binary Alloy authors, so no repo can ever carry it, and a distro whose headline surface is its console cannot ship without one. It is built on `fedora:43` rather than on the dev box so the toolchain and glibc match the runtime stage.
|
| 98 |
|
- |
- [x] sr.ht account: **`~maxmj`** for v0. LLC-owned `~makecreative` remains the long-term target; migration if/when the project grows.
|
|
106 |
+ |
- [ ] **An always-on x86_64 builder.** The blocker under "CI" above, and the thing the signing key and the weekly base-update rebuild both wait on. astra is always-on and aarch64; fw13 is x86_64 and sleeps.
|
|
107 |
+ |
- [x] Source hosting: **`makenot.work/git/max/alloy`**, our own platform. The old answer here was the sr.ht account `~maxmj` for v0 with LLC-owned `~makecreative` as the long-term target; sourcehut is now a backup remote and that migration question retires with it.
|
| 99 |
108 |
|
- [x] **Publish `:latest`, `:<fedora-version>`, and `:<fedora-version>-YYYYMMDD` tags.** Currently `:latest`, `:43`, `:43-YYYYMMDD`. `:latest` for casual users, the bare version for version-pinned users, the dated tag for reproducibility. Wired up when distribution starts.
|