From fa9d75de98325fdd8f5c0c1f6b7018934438c65a Mon Sep 17 00:00:00 2001 From: archipelago Date: Fri, 7 Aug 2026 12:25:44 -0400 Subject: [PATCH] =?UTF-8?q?fix(release):=20track=20the=20registry=20trust?= =?UTF-8?q?=20floor=20=E2=80=94=20releases/**=20was=20swallowing=20it?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit d0af38e8 shipped check-catalog-registry-trust.py without the file it reads: `releases/**` in .gitignore silently dropped registry-trust-floor.json, so the guard would have failed in CI and on any fresh clone. app-catalog.json only stays tracked because it predates that rule. Both are source rather than build output — nodes fetch the catalog from this path on main, and the floor is what the guard checks it against — so both now have explicit negations, with the reason recorded next to them. Co-Authored-By: Claude Opus 5 (1M context) --- .gitignore | 7 +++++++ releases/registry-trust-floor.json | 33 ++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) create mode 100644 releases/registry-trust-floor.json diff --git a/.gitignore b/.gitignore index 7aacbbb6..e2e7fdcf 100644 --- a/.gitignore +++ b/.gitignore @@ -62,6 +62,13 @@ coverage/ releases/** !releases/ !releases/manifest.json +# The signed app catalog and the registry trust floor are source, not build +# output: nodes fetch the catalog from this path on main, and the floor is what +# scripts/check-catalog-registry-trust.py checks it against. Both were being +# swallowed by the rule above — app-catalog.json only stayed tracked because it +# predates it. +!releases/app-catalog.json +!releases/registry-trust-floor.json # Image recipe output image-recipe/output/ diff --git a/releases/registry-trust-floor.json b/releases/registry-trust-floor.json new file mode 100644 index 00000000..4f71cbe3 --- /dev/null +++ b/releases/registry-trust-floor.json @@ -0,0 +1,33 @@ +{ + "_comment": [ + "Registry hosts that binaries ALREADY DEPLOYED to nodes are known to trust.", + "", + "This is the floor the signed app catalog must stay within. It is NOT the", + "same as TRUSTED_REGISTRIES in the working tree: that list describes what a", + "binary being built today accepts, while nodes in the field run whatever was", + "shipped to them. Publishing a catalog that names a host the fleet's binaries", + "do not trust makes every install fail with 'not from a trusted registry'.", + "", + "To migrate to a new registry host, in this order:", + " 1. Add the host to TRUSTED_REGISTRIES and ship a binary OTA.", + " 2. Confirm the fleet is running that binary or newer.", + " 3. Add the host here, in the same commit as the confirmation.", + " 4. Only then regenerate and re-sign the catalog against the new host.", + "", + "Removing a host is the mirror image: take it out of the catalog first, let", + "that catalog reach every node, and only then drop it from here." + ], + "hosts": [ + "docker.io", + "ghcr.io", + "localhost", + "146.59.87.168:3000" + ], + "pending": { + "source.archipelago-foundation.org": { + "trusted_from_binary": "unreleased", + "note": "Added to TRUSTED_REGISTRIES 2026-08-07. Not yet shipped in any OTA, so no deployed node accepts it. Promote to `hosts` only after the fleet is confirmed on a binary that includes it." + } + }, + "updated": "2026-08-07" +}