fix(backup): give binjovi-plans and hetzner-node-image an off-cluster copy #585
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/backup-plans-and-node-image"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Two repositories had no off-cluster backup of any kind. Measured on 2026-09-10 with an authenticated Codeberg read — not inferred from manifests:
Of the 45 repositories on the instance, 39 have a push mirror.
seanfarmandplatform-seanfarmare covered through Codeberg as the Flux bootstrap source. These two had nothing: noForgejoPushMirror, absent fromrepository-bootstrap.json, absent fromForgejoRepositoryBindings.hetzner-node-imagewas created byforgejo-users/hetzner-image-repository.sh, a one-repo bootstrap that usesauto_init: true— so a coldmake rebuildrecreated it empty, with one initial commit and nothing to restore from.What was at risk
binjovi-plansholds the project definitions and the canonical RustFS bucket, policy and identity declarations thatrustfs-identities/{loki,zdnspromote,binjovi-rpg-build,binjovi-rpg-promote}.yamlall name as their source of truth. Code can be rebuilt from a running node; those declarations exist nowhere else.hetzner-node-imageholds the disk assembly recipe for the image that boots every node.gitmirrors/README.mdrecordssean/linuxdestroyed on 2026-05-31 with Codeberg as the only other copy.Change
ForgejoPushMirrorfor each,branchFilter: main,trunk. Both branches exist on both repositories (git ls-remote). A non-empty filter is what stops Forgejo building the bidirectional--mirrorremote that rewrote localmainin 2026-07; a filter naming an absent branch fails the whole push atomically, which broke 11/28 repositories on 2026-08-11.repository-bootstrap.jsonwith a source, so a cold rebuild imports content rather than creating an empty shell. Jobcompletions40 -> 42, and the test now derives that from the record count instead of repeating the literal.hetzner-node-imageadded tomanagement-grants-repositories.txt, which it was missing.binjovi-planswas already present.scripts/check-repository-backup.sh, run for both beforemake rebuilddestroys anything. It is the general form ofcheck-kernel-source-backup.shminus the kernel-only size ceiling.Neither file declares a
ForgejoRepository. Both repositories already exist and are created elsewhere; a repository CR would only be one more object to remove when binjovi takes over the declaration.Guard changes, with controls
tests/gitmirror-fleet.shrequired exactly oneForgejoRepositoryper file. It now recognises mirror-only files through a short explicit list. Both controls confirmed red before this landed:binjovi-plansfrom the list ->FAIL: has 0 ForgejoRepository docs, want 1ForgejoRepositoryto a mirror-only file ->FAIL: is mirror-only but has 1 ForgejoRepository docsThe new backup guard was proven both ways too:
bytey(mirrored) passes; both target repositories fail naming the exact refs.Passing now:
gitmirror-fleet(36 repositories, 38 mirrors),binjovi-repository-bootstrap,binjovi-service-handoff,hetzner-image-repository.MERGE ORDER — please read
The two Codeberg repositories must be created before this merges. A push mirror whose remote does not exist never delivers, and the new rebuild guards will refuse to destroy until the refs match. That refusal is correct — there genuinely is no backup — but it blocks
make rebuilduntil the backup is real.I could not create them: the local harness refused the authenticated write to codeberg.org. The command is in the PR discussion.
Not in scope here
service-legacy-access.yamlis untouched. Itsforgejorepositoriesrule lists legacy CR names, and neither repository is inForgejoRepositoryBindingsyet, so neither has a service handle to authorize. That belongs with the binjovi-side work. Worth noting separately: that rule has 40 names against 41 bindings —hermesis missing, so its adoption fails withdeniedrather thanlegacy_controller_present.https://claude.ai/code/session_01TdW5FSvRJW8CtGnpd29Xp8
de2469cc08766f41323f766f41323f3b9ee46ced