If a term is unfamiliar, check the shared glossary first:
docs/glossary.md
This page explains how this repository chooses an upstream akmods source ref, when to use a temporary pin, and when to let floating tracking heal itself.
Current control points:
- checked-in defaults file
ci/defaults.json - manual environment overrides when you need one-off validation
The repo supports three resolution modes, checked in order:
- Explicit environment override. If
AKMODS_UPSTREAM_REForDEFAULT_AKMODS_REFis set in the process environment, that value wins. This is the escape hatch for debugging a specific upstream commit. - Explicit pin in
ci/defaults.json. If theAKMODS_UPSTREAM_REFfield inci/defaults.jsonis non-empty, that commit is used. This is how you freeze the repo to a known-good SHA during an outage. - Floating tracking ref. Otherwise,
AKMODS_UPSTREAM_TRACK(default"main") is resolved viagit ls-remoteagainstAKMODS_UPSTREAM_REPOat the start of every run, and the resulting SHA is pinned for the rest of the run.
The floating mode is the self-healing default. A transient upstream mismatch stays red until upstream lands a compatible commit, at which point the next cron run picks it up without any human edit.
Every build records the resolved commit SHA in two places:
- the workflow
build-inputsmanifest artifact, so you can trace any run to the SHA it resolved - an OCI image label
org.zfs-aurora-complex.akmods-ref
Warning
akmods-ref is only guaranteed accurate on a build that actually rebuilt the shared
akmods cache. Both records above hold the SHA this run resolved, which is not
necessarily the SHA that produced the ZFS modules in the image.
On a cache-reuse build — the common case, since most runs reuse — the cache may have been built days earlier against an older commit while the tracking ref has since moved. The label still reports the freshly resolved SHA, so it can name a commit that never touched the modules being shipped. Do not treat it as proof of module provenance.
What is always accurate is org.zfs-aurora-complex.akmods-image: the digest-pinned ref
of the exact cache image the build consumed, verified by
ci_tools/check_akmods_cache.py to contain the
required kmod-zfs RPM and to carry a valid signature. When tracing what a published
image really contains, start from that digest, not from akmods-ref.
- Reproducibility of a specific run. Use
ci/inputs.lock.jsonreplay mode to restore a prior run's base image, build container, and OpenZFS version. Note the lock file does not carry the akmods commit — setAKMODS_UPSTREAM_REFexplicitly to replay a specific upstream commit, or the replay will resolve the current tracking ref instead. - Debugging. Pinning short-term isolates the akmods side while you chase a build failure.
- Emergency freeze. If upstream lands a change you actively do not trust, setting the
ci/defaults.jsonpin freezes the repo to the last known-good SHA until you choose to unfreeze it.
You usually should not bump this pin on a cadence.
The daily build.yml cron re-resolves base image, kernel set, and akmods cache on every run. A red build caused by a temporary upstream mismatch (new Fedora kernel, no matching OpenZFS release yet) is expected and self-heals once upstream catches up — the stable tag does not move while the candidate is red, so users see the last known-good image. See docs/upstream-change-response.md for the full decision table.
Setting or moving an explicit AKMODS_UPSTREAM_REF is the right move only when:
- a newer akmods fork commit is known to support the current Fedora kernel, and waiting for the floating tracking ref will not pick it up
- you need to reproduce or debug a specific failing build against an exact upstream SHA
- the fork made a breaking change (cache layout, publish naming, dependency set) that requires freezing the build to a known-good SHA while you adapt
Otherwise: leave it alone and let the cron retry.
Under the floating-ref default, there is no routine update process — the cron resolves AKMODS_UPSTREAM_TRACK every run.
If you do need to pin (to debug, to freeze during an upstream outage, or to reproduce a specific past build):
- inspect the current state of
Danathar/akmods - choose the exact commit you want to test
- set
AKMODS_UPSTREAM_REFinci/defaults.jsonto that SHA - run branch or manual validation first if the change is risky
- merge only after
mainbuilds and signs successfully - when the outage clears, set
AKMODS_UPSTREAM_REFback to""so the floating ref resumes
The two processes above are about which fork commit this repo consumes. This
section is about maintaining the fork itself: pulling new commits from
ublue-os/akmods (the upstream remote) into Danathar/akmods so the floating
main ref keeps gaining upstream ZFS and build fixes.
Because main floats by default, a fork sync is what feeds new upstream work
into this repo's next build. Sync periodically, and especially when a new Fedora
kernel needs an upstream ZFS compatibility fix.
A sync is not a clean fast-forward. The fork carries local customizations that this repo depends on, and they collide with upstream changes in the same files. Procedure:
- in the
Danathar/akmodscheckout, fetch both remotes:git fetch upstream && git fetch origin - branch from the fork tip:
git switch main && git pull && git switch -c sync/upstream-main - merge upstream:
git merge upstream/main(expect a conflict, see below) - resolve, validate, then merge the branch into
mainand push the fork only after validation passes
The fork's load-bearing customizations live in the Justfile and conflict with
upstream every time upstream touches the same variable block. Resolve by
combining, never by taking one side wholesale:
- keep the fork's
akmods_name := env('AKMODS_IMAGE_NAME', shell(yq + ' "...name" images.yaml', ...))line. This derives the published image name fromimages.yaml.name, whichci_tools/akmods_configure_zfs_target.pysets per run. Taking upstream's hardcodedakmods-<target>instead would make the cache publish under the wrong name and silently break cache reuse here. - adopt upstream's
yqvariable form (shell(yq + ' ...')) for everyimages.yamlread, including theakmods_nameline above. Upstream'syq := 'yq --yaml-fix-merge-anchor-to-spec'is required by newer yq for the merge anchors inimages.yaml; this repo's configure step uses the same flag. - preserve the fork's OpenZFS-release-discovery token hardening (the
--secret=id=github_tokenplumbing in thebuild/testrecipes and the xtrace/JSON-array guards inbuild_files/zfs/build-kmod-zfs.sh).
Before pushing the fork:
- no conflict markers remain:
grep -rn '^<<<<<<<\|^>>>>>>>' . - the
Justfileparses and resolves:AKMODS_KERNEL=main AKMODS_VERSION=<fedora> AKMODS_TARGET=common just --evaluatesucceeds - with the zfs target configured (as this repo does),
akmods_nameresolves to the cache repo name, notnull bash -n build_files/zfs/build-kmod-zfs.shpasses- after pushing, run this repo's
build-branchworkflow (or a manualbuild.ymlwithrebuild_akmods=true) so a real akmods build validates the synced fork beforemainfloats onto it
- new Fedora kernel behavior where the tracking ref is not yet usable but a known-good commit is available
- upstream changes around cache layout, dependency lists, or image publishing that need isolated validation
- changes required for future Fedora majors
Build Shared ZFS Akmods Cachestill succeeds- shared cache image contains the
kmod-zfsRPM needed for the supported primary kernel - final candidate image still installs ZFS userspace and modules correctly
- promotion and signing still succeed on
main
The moving pieces are:
- the configured fork repository:
Danathar/akmods - the tracking ref or explicit pin configured in
ci/defaults.json - the resolved commit SHA, meaning the exact Git commit ID used for one run
- the temporary clone the workflow run creates in
/tmp/akmods
How they relate:
- the workflow run still uses the configured fork as the source repository
- the workflow run resolves the selected ref to one exact commit SHA before cloning
- the workflow run uses that resolved commit, not a branch that can move mid-build
- that clone in
/tmp/akmodsexists only for the current run - when the run ends, that temporary checkout is discarded
Most important consequence:
- when the floating
AKMODS_UPSTREAM_TRACKref is active (default), pushing a new commit toDanathar/akmodson that ref becomes the source for the next build - when
AKMODS_UPSTREAM_REFis set inci/defaults.jsonor the environment, pushing new upstream commits does not change this repo's builds until that pin is cleared or moved
If a new akmods pin breaks the build, revert the pin first. Do not start patching unrelated workflow code until you know the akmods change is really required.
This repository no longer patches the cloned akmods Justfile at runtime.
That means:
- if this repo needs repo-specific publish-name behavior, that logic must exist in the pinned
Danathar/akmodscommit itself - the clone step here is intentionally boring on purpose: clone, check out the exact commit, verify the commit SHA, stop
- if a future akmods change breaks repo-specific publishing, fix the fork and repin it instead of reintroducing a local patch layer