Hold the pinned image against the repository's schema

Schema v4 gave the deployment a silent drift surface: the pinned pair is
self-consistent, migrating to 3 and serving 3, while this repository has
moved to 4. That reads as healthy, which makes it worse than an error —
the failure is the assumption that the deployment records approver
principal type.

Document v4 in storage-operations, state in the deploy runbook that the
pin predates it, and add a test that requires the statement whenever the
release record's schema version differs from this repository's. Verified
to fail when the acknowledgement is removed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HyybaE7DUXrWYrhbnESCTe

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 1275879@bnt-lap001
Assistant-Session: eb464208-f821-41b2-bc5a-a6c33d92a8ad
This commit is contained in:
tegwick 2026-09-09 14:38:21 +02:00
parent 92043cfe51
commit fec4eaeb1b
4 changed files with 88 additions and 0 deletions

View file

@ -11,8 +11,12 @@ from __future__ import annotations
import re
from pathlib import Path
from approval_engine.store import LATEST_SCHEMA_VERSION
ROOT = Path(__file__).resolve().parents[1]
MANIFEST = ROOT / "deploy" / "approval-engine.yaml"
RELEASE_RECORD = ROOT / "docs" / "image-scan-2026-09-06.md"
DEPLOY_README = ROOT / "deploy" / "README.md"
IMAGE_LINE = re.compile(r"^\s*image:\s*(\S+)\s*$", re.MULTILINE)
DIGEST_PIN = re.compile(r"^[^\s@]+@sha256:[0-9a-f]{64}$")
@ -67,3 +71,42 @@ def test_deploy_readme_does_not_instruct_replacing_a_pinned_placeholder():
readme = (ROOT / "deploy" / "README.md").read_text(encoding="utf-8")
if "REPLACE_WITH_RELEASE_DIGEST" not in manifest:
assert "replace `REPLACE_WITH_RELEASE_DIGEST`" not in readme
def test_pinned_image_schema_drift_is_acknowledged():
"""The pin can silently fall behind the repository's schema.
The checks above hold that migrate and serve run the *same* code. They
cannot see that both run *old* code: a v3 image migrating to 3 and serving
3 is perfectly self-consistent while this repository has moved to 4. That
reads as healthy and is the more dangerous shape, because the failure is an
assumption ("the deployment records principal_type") rather than an error.
So when the manifest still pins the artifact the release record describes,
the record's schema version must either match this repository or the
runbook must say plainly that the pin is behind. Prose alone loses that;
the test makes stating it the cheaper option.
"""
refs = image_refs()
assert refs, "no image references found"
pinned = refs[0].split("@", 1)[-1]
record = RELEASE_RECORD.read_text(encoding="utf-8")
if pinned not in record:
return # a newer artifact is pinned; this record no longer describes it
versions = {
int(v) for v in re.findall(r"LATEST_SCHEMA_VERSION\s*=\s*(\d+)", record)
}
assert len(versions) == 1, f"release record states {versions or 'no'} schema versions"
recorded = versions.pop()
if recorded == LATEST_SCHEMA_VERSION:
return
readme = DEPLOY_README.read_text(encoding="utf-8")
assert f"predates schema v{LATEST_SCHEMA_VERSION}" in readme, (
f"pinned image records schema v{recorded} while this repository is at "
f"v{LATEST_SCHEMA_VERSION}; deploy/README.md must say so explicitly "
f"(the phrase 'predates schema v{LATEST_SCHEMA_VERSION}') or the "
"manifest must be re-pinned to a newer artifact"
)