feat(release): guard the catalog against publishing untrusted registry hosts
Encodes the sequencing rule that nearly shipped a fleet-wide outage today. The signed catalog is authoritative on every node — catalog_image_override makes its image refs beat the on-disk manifest. TRUSTED_REGISTRIES in the working tree describes a binary being built now; nodes run whatever was last shipped to them. Those two diverge for exactly as long as an OTA takes to reach the fleet, and that window is when regenerating the catalog silently breaks every install with "not from a trusted registry". Regenerating today would have done precisely that: the generator embeds each app's manifest, and those now name the new registry domain, which no deployed binary trusts. - releases/registry-trust-floor.json records the hosts DEPLOYED binaries trust, separately from what the source tree accepts, with the new domain parked under `pending` until an OTA carries it. The migration order is written down there rather than living in someone's memory. - scripts/check-catalog-registry-trust.py compares the catalog's hosts against that floor and explains the ordering fix when they diverge. - sign-catalog.sh runs it as a preflight BEFORE prompting for the mnemonic, so a bad catalog is refused at the last reversible moment. - CI runs it blocking, plus the drift report advisory (drift between a manifest landing and the next signed release is expected, since only the ceremony can close it). Also installs PyYAML in the manifests job. That job passed only because GitHub runners happen to ship ruby, which the validator used to require; it now needs python3+PyYAML. Verified: passes on the published catalog (2 hosts, both trusted); refuses a simulated full regenerate (79 refs on the untrusted domain) and blocks the ceremony without requesting the mnemonic. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
7cf6980894
commit
d0af38e825
@@ -93,8 +93,25 @@ jobs:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install YAML parser
|
||||
run: python3 -m pip install --quiet pyyaml
|
||||
|
||||
- name: Validate manifests
|
||||
run: |
|
||||
for manifest in apps/*/manifest.yml; do
|
||||
./scripts/validate-app-manifest.sh --repo-audit "$manifest"
|
||||
done
|
||||
|
||||
# The signed catalog overrides on-disk manifests on every node, so a
|
||||
# catalog naming a registry host the deployed fleet does not trust breaks
|
||||
# every install fleet-wide. Blocking, and cheap.
|
||||
- name: Catalog registry trust floor
|
||||
run: python3 scripts/check-catalog-registry-trust.py
|
||||
|
||||
# Advisory: shows where the release catalog has fallen behind the
|
||||
# manifests in this repo. Not blocking, because the catalog can only be
|
||||
# updated through the signing ceremony, so drift is expected between a
|
||||
# manifest landing and the next signed release.
|
||||
- name: Catalog drift (advisory)
|
||||
continue-on-error: true
|
||||
run: python3 scripts/check-app-catalog-drift.py --catalog releases/app-catalog.json --release
|
||||
|
||||
Reference in New Issue
Block a user