Justfile: domain-derived tags for update/bootstrap (idiot-proof box roles)
closedGoal
Make just update / just bootstrap idiot-proof: the operator picks a correctly-constructed domain name and the Justfile derives the box role and ansible-playbook tags. No YAML spelunking, no silent partial converges from a missing --tags.
Domain → role → tags
infra.sovrn.at— exact match — metrics box →--tags common,secrets,metrics-boxmxb.<region>.sovrn.at—^mxb\.[a-z0-9-]+\.sovrn\.at$— pri-20 store-and-forward relay →--tags common,secrets,stalwart-backup-secret,stalwart-backup-install,caddy,stalwart-backup-bootstrap,stalwart-backup-relay,telemetry-edge(full backup slice, bug d43eebe)mx<N>.<region>.sovrn.at—^mx[0-9]+\.[a-z0-9-]+\.sovrn\.at$— cell box → full run, no--tags- Anything else (
sovrn.at,infra.sovrn.at, unknown) → loud fail before Ansible runs, message lists the three valid shapes.
Bare --tags metrics-box alone is NOT enough for a fresh infra box: common creates the sovrn user/group, base dirs, firewall (common/tasks/main.yml), and metrics_box chowns to {{ sovrn_user }}. Same logic drives the full backup slice (relay needs common + caddy for the ACME challenge proxy + telemetry-edge so it is not blind).
Lifecycle coverage
- Build cell:
provision-zds-secrets CELL(validates mxN shape) →bootstrap CELL→persist-bootstrap-secrets CELL→update CELL. - Build infra:
provision-metrics-secret+ vault edit →update infra.sovrn.at. No bootstrap / recovery / host-vault / stalwart-binary path. - Build relay:
bootstrap mxb…→persist-bootstrap-secrets mxb…→update mxb…. Relay credential generation requiresmode=bootstrap(stalwart/tasks/secret.yml,stalwart_backup/secret.yml), sobootstrapaccepts mxN and mxb, refuses infra + unknown. - Cell sick:
recovery-backup CELL→ manual provider move →recovery-bootstrap CELL→ relay-drain verify. Bothrecovery-*are mxN-only; on infra/relay they fail loudly (“no state to recover — wipe +update; drain the relay queue first perrelay-drain-verify.md”). - Update in place:
update <cell|infra.sovrn.at|mxb…>with automatic tags.updaterejects user-supplied--tags/--skip-tagsin ARGS and points at newupdate-slice TARGET *ARGSescape hatch (canary edge, caddy-only, relay map-only runbooks). _precheckderives box type from the domain (not inventory groups): stalwart binary required for cell+relay only, host vault for cell+relay, ZDS secrets for cell only; keeps inventory-membership check + mismatch warning.
Verification
bash -non rendered recipes,just --dry-runper shape.- Regex matrix: valid
infra.sovrn.at,mx1.eu.sovrn.at,mxb.eu.sovrn.at; invalidsovrn.at,infra.sovrn.at,mx.eu.sovrn.at,MX1.eu.sovrn.at. --tagsrejection,STAGING=1preserved on bootstrap.
3 Comments
Implemented (working copy, uncommitted)
Domain-derived box roles in
Justfile; operator picks only the domain name.update: injects--tags common,secrets,metrics-boxforinfra.rtw.run, the full d43eebe backup slice formxb.<region>.sovrn.at, no--tagsformxN.<region>.sovrn.at; unknown domains fail loudly. User--tags/--skip-tagsrejected with pointer to newupdate-sliceescape hatch (canary edge, caddy-only, relay map-only).bootstrap: accepts cell + relay (relay credential generation requiresmode=bootstrap), refusesinfra.rtw.run+ unknown; still rejects user tags, keepsSTAGING.recovery-backup/recovery-bootstrap: cell-only gates placed before any side effects (incl. before host-key rotation); infra/relay get wipe+redeploy pointers + relay-drain warning.provision-zds-secrets: cell-only.persist-bootstrap-secrets: cell+relay._precheck: role from domain (single source of truth); stalwart binary required cell+relay only, host vault cell+relay, ZDS secrets cell only; keeps inventory-membership check + new domain/inventory mismatch warning.Verification (fresh, this session)
/tmp/opencode/verify-justfile-gates.py, extracts real recipe bodies, stubs externals): 25⁄25 pass — valid shapes proceed with correct tags,sovrn.at/infra.sovrn.at/mx./MX1.rejected,--tagsrejected, recovery gates fire before keyscan.bash -nclean on all 8 touched recipe bodies;just --dry-runrenders correctly; livejust update mx1.eu.sovrn.at --tags fooandjust bootstrap sovrn.atfail with the intended messages.infra.sovrn.at/ stale-tag references left inJustfile.Note (not mine)
Working copy also contains a modification to
deployment/inventory/host_vars/mx99.eu.sovrn.at/vault.ymlplus deletion ofdeployment/.local/stalwart-secret.mx99.eu.sovrn.at(~12:11 UTC) — predates/concurrent with this work; every script I executed ran with--dry-run(verified the persist/provision scripts return before any write/shred in that mode). Left untouched; flagging so it isn’t mistaken for part of this change. Nothing committed.Correction: the metrics-box domain is infra.sovrn.at (the earlier infra.rtw.run was a mix-up). Justfile, scripts, tests, and docs now consistently use infra.sovrn.at, which matches inventory/hosts.yml.
Complete: domain-derived Justfile tags for update/bootstrap/recovery (cells, infra.sovrn.at, mxb.) are landed and covered by deployment/scripts/test-deploy. Closing.