Merge commit 'd7356ef76e26cd461278de18cd471d7cb2682043'

Change-source: pulse-maintainer
This commit is contained in:
pulse-triage[bot]
2026-09-04 14:29:39 +01:00
4 changed files with 437 additions and 9 deletions
+67 -6
View File
@@ -78,6 +78,62 @@ jobs:
--diagnostic release-continuity-evidence/release-diagnostic.json \
--github-output "${GITHUB_OUTPUT}"
- name: Reject orphaned stable publication tags
id: frontier
if: ${{ !cancelled() && steps.release.outputs.referenceable == 'true' }}
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
run: |
set -euo pipefail
evidence=release-continuity-evidence
gh api --paginate --slurp \
-H 'Accept: application/vnd.github+json' \
-H 'X-GitHub-Api-Version: 2026-03-10' \
"repos/${REPOSITORY}/git/matching-refs/tags/v?per_page=100" \
> "${evidence}/stable-refs.json"
gh api --paginate --slurp \
-H 'Accept: application/vnd.github+json' \
-H 'X-GitHub-Api-Version: 2026-03-10' \
"repos/${REPOSITORY}/releases?per_page=100" \
> "${evidence}/releases.json"
fetch_registry_tags() {
local registry_name="$1" auth_url="$2" registry_url="$3" image="$4" output="$5"
local token
token="$(curl -fsSL --retry 4 --retry-delay 2 --retry-all-errors "${auth_url}")"
token="$(jq -er '.token | select(type == "string" and length > 0)' <<<"${token}")"
curl -fsSL --retry 4 --retry-delay 2 --retry-all-errors \
-H "Authorization: Bearer ${token}" \
"${registry_url}/v2/${image}/tags/list?n=10000" \
| jq --arg name "${registry_name}/${image}" '.name = $name' > "${output}"
}
owner="${GITHUB_REPOSITORY_OWNER,,}"
for image in pulse pulse-control-plane; do
file_image="${image//-/_}"
fetch_registry_tags \
ghcr.io \
"https://ghcr.io/token?service=ghcr.io&scope=repository:${owner}/${image}:pull" \
https://ghcr.io "${owner}/${image}" \
"${evidence}/ghcr-${file_image}-tags.json"
done
# The server image is public on both registries. The control-plane
# image is publicly enumerable only on GHCR, so an unauthenticated
# continuity audit must not depend on Docker Hub credentials.
fetch_registry_tags \
docker.io \
"https://auth.docker.io/token?service=registry.docker.io&scope=repository:rcourtman/pulse:pull" \
https://registry-1.docker.io rcourtman/pulse \
"${evidence}/docker-pulse-tags.json"
python3 scripts/release_control/release_continuity.py frontier \
--release-json "${evidence}/release.json" \
--stable-refs-json "${evidence}/stable-refs.json" \
--releases-json "${evidence}/releases.json" \
--registry-tags-json "${evidence}/ghcr-pulse-tags.json" \
--registry-tags-json "${evidence}/docker-pulse-tags.json" \
--registry-tags-json "${evidence}/ghcr-pulse_control_plane-tags.json" \
--diagnostic "${evidence}/frontier-diagnostic.json"
- name: Bind the release activation marker
id: activation
# A structurally valid tag/id/SHA remains safe lookup data even when
@@ -114,7 +170,7 @@ jobs:
- name: Verify immutable release and build provenance
id: packet
if: ${{ always() && steps.release.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
if: ${{ always() && steps.release.outcome == 'success' && steps.frontier.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
@@ -127,7 +183,7 @@ jobs:
- name: Authenticate every published release asset
id: assets
if: ${{ always() && steps.release.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
if: ${{ always() && steps.release.outcome == 'success' && steps.frontier.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
env:
PULSE_UPDATE_SIGNING_PUBLIC_KEY: ${{ vars.PULSE_UPDATE_SIGNING_PUBLIC_KEY }}
REPOSITORY: ${{ github.repository }}
@@ -136,7 +192,7 @@ jobs:
- name: Verify exact-version container identities
id: containers
if: ${{ always() && steps.release.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
if: ${{ always() && steps.release.outcome == 'success' && steps.frontier.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
@@ -158,7 +214,7 @@ jobs:
- name: Verify stable container discovery aliases
id: aliases
if: ${{ always() && steps.release.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
if: ${{ always() && steps.release.outcome == 'success' && steps.frontier.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
env:
TAG: ${{ steps.release.outputs.tag }}
EXPECTED_SERVER_DIGEST: ${{ steps.activation.outputs.server_image_digest }}
@@ -171,7 +227,7 @@ jobs:
- name: Verify exact-version Helm identity
id: helm
if: ${{ always() && steps.release.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
if: ${{ always() && steps.release.outcome == 'success' && steps.frontier.outcome == 'success' && steps.activation.outcome == 'success' && github.event.schedule != '17 */6 * * *' }}
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
@@ -202,6 +258,7 @@ jobs:
CONTROL_PLANE_IMAGE_DIGEST: ${{ steps.activation.outputs.control_plane_image_digest }}
HELM_CHART_DIGEST: ${{ steps.activation.outputs.helm_chart_digest }}
RELEASE_RESULT: ${{ steps.release.outcome }}
FRONTIER_RESULT: ${{ steps.frontier.outcome }}
ACTIVATION_RESULT: ${{ steps.activation.outcome }}
PACKET_RESULT: ${{ steps.packet.outcome }}
ASSET_RESULT: ${{ steps.assets.outcome }}
@@ -216,7 +273,7 @@ jobs:
if [ "${TRIGGER_SCHEDULE}" = '17 */6 * * *' ]; then
mode=release_lock
fi
for diagnostic in release activation; do
for diagnostic in release frontier activation; do
path="release-continuity-evidence/${diagnostic}-diagnostic.json"
if [ ! -s "${path}" ]; then
jq -n \
@@ -227,6 +284,7 @@ jobs:
done
jq -n \
--slurpfile release_diagnostic release-continuity-evidence/release-diagnostic.json \
--slurpfile frontier_diagnostic release-continuity-evidence/frontier-diagnostic.json \
--slurpfile activation_diagnostic release-continuity-evidence/activation-diagnostic.json \
--arg schema_version "1" \
--arg checked_at "${checked_at}" \
@@ -248,6 +306,7 @@ jobs:
--arg control_plane_image_digest "${CONTROL_PLANE_IMAGE_DIGEST}" \
--arg helm_chart_digest "${HELM_CHART_DIGEST}" \
--arg release_result "${RELEASE_RESULT}" \
--arg frontier_result "${FRONTIER_RESULT}" \
--arg activation_result "${ACTIVATION_RESULT}" \
--arg packet_result "${PACKET_RESULT}" \
--arg asset_result "${ASSET_RESULT}" \
@@ -281,10 +340,12 @@ jobs:
},
diagnostics: {
release_identity: $release_diagnostic[0],
stable_publication_frontier: $frontier_diagnostic[0],
activation_binding: $activation_diagnostic[0]
},
checks: {
release_resolution: $release_result,
stable_publication_frontier: $frontier_result,
activation_binding: $activation_result,
immutable_packet_and_provenance: $packet_result,
authenticated_assets: $asset_result,
@@ -161,12 +161,23 @@ func TestSecurityScanRevalidatesLatestStableDelivery(t *testing.T) {
`"repos/${REPOSITORY}/releases/latest"`,
`scripts/release_control/release_continuity.py release`,
"release-diagnostic.json",
"Reject orphaned stable publication tags",
`"repos/${REPOSITORY}/git/matching-refs/tags/v?per_page=100"`,
`"repos/${REPOSITORY}/releases?per_page=100"`,
"https://ghcr.io/token?service=ghcr.io&scope=repository:",
"https://auth.docker.io/token?service=registry.docker.io&scope=repository:",
`"${registry_url}/v2/${image}/tags/list?n=10000"`,
`--registry-tags-json "${evidence}/ghcr-pulse-tags.json"`,
`--registry-tags-json "${evidence}/docker-pulse-tags.json"`,
`scripts/release_control/release_continuity.py frontier`,
"frontier-diagnostic.json",
"Bind the release activation marker",
`!cancelled()`,
`steps.release.outputs.referenceable == 'true'`,
`scripts/release_control/release_continuity.py activation`,
"activation-diagnostic.json",
`steps.activation.outcome == 'success'`,
`steps.frontier.outcome == 'success'`,
`./scripts/verify-github-release-integrity.sh`,
`./scripts/validate-published-release.sh`,
`PULSE_UPDATE_SIGNING_PUBLIC_KEY: ${{ vars.PULSE_UPDATE_SIGNING_PUBLIC_KEY }}`,
@@ -177,6 +188,7 @@ func TestSecurityScanRevalidatesLatestStableDelivery(t *testing.T) {
`stable_container_aliases: $alias_result`,
`activation_binding: $activation_result`,
`release_identity: $release_diagnostic[0]`,
`stable_publication_frontier: $frontier_diagnostic[0]`,
`CONVERGENCE_RUN_ID: ${{ github.event.workflow_run.id }}`,
`TRIGGER_SCHEDULE: ${{ github.event.schedule }}`,
`mode=release_lock`,
@@ -229,6 +241,7 @@ func TestSecurityScanRevalidatesLatestStableDelivery(t *testing.T) {
step := workflowStepBlock(t, workflowJobBlock(t, workflow, "release-continuity"), stepName)
for _, admission := range []string{
`steps.release.outcome == 'success'`,
`steps.frontier.outcome == 'success'`,
`steps.activation.outcome == 'success'`,
} {
if !strings.Contains(step, admission) {
+237 -1
View File
@@ -29,6 +29,10 @@ IMMUTABLE_REPLACEMENT_ACTION = (
"Do not edit or repair the advertised release in place; restore the last known-good "
"stable target if needed, then publish a corrected replacement through convergence."
)
ORPHAN_REPLACEMENT_ACTION = (
"Do not advertise or repair the orphaned version in place; inspect the failed "
"release run and publish a corrected replacement through convergence."
)
@dataclass(frozen=True)
@@ -86,6 +90,27 @@ RELEASE_RULES = {
}
FRONTIER_RULES = {
"frontier_payload_invalid": (
"GitHub did not return complete stable-tag and release inventories.",
"Inspect the matching-refs and releases API responses before retrying.",
),
"stable_tag_without_release": (
"A stable source tag newer than the advertised release has no GitHub Release packet.",
ORPHAN_REPLACEMENT_ACTION,
),
"newer_stable_release_not_advertised": (
"A published stable release is newer than the advertised latest release.",
"Inspect the latest-release selection and customer aliases; do not move them without "
"an immutable activation packet and successful convergence.",
),
"registry_stable_tag_beyond_latest": (
"A public container registry exposes a stable version newer than the advertised release.",
ORPHAN_REPLACEMENT_ACTION,
),
}
ACTIVATION_RULES = {
"activation_asset_invalid": (
"The release does not list one uploaded, digest-bound activation marker.",
@@ -270,6 +295,185 @@ def release_is_referenceable(payload: Any, failures: list[Violation]) -> bool:
)
def stable_version(tag: str) -> tuple[int, int, int]:
if STABLE_TAG.fullmatch(tag) is None:
raise ValueError(f"invalid stable tag {tag!r}")
parts = tuple(int(part) for part in tag.removeprefix("v").split("."))
return (parts[0], parts[1], parts[2])
def inventory_list(payload: Any) -> list[Any] | None:
"""Flatten gh api's ordinary or --slurp pagination representation."""
if not isinstance(payload, list):
return None
if payload and all(isinstance(page, list) for page in payload):
return [item for page in payload for item in page]
return payload
def frontier_violations(
latest_release: Any,
stable_refs_payload: Any,
releases_payload: Any,
registry_payloads: list[Any],
) -> tuple[list[Violation], dict[str, Any]]:
refs = inventory_list(stable_refs_payload)
releases = inventory_list(releases_payload)
latest_tag = latest_release.get("tag_name") if isinstance(latest_release, dict) else None
identity: dict[str, Any] = {
"advertised_tag": latest_tag,
"newer_stable_tags": "",
"orphaned_stable_tags": "",
"unadvertised_published_stable_tags": "",
"registry_stable_tags_beyond_latest": "",
}
if (
not isinstance(latest_tag, str)
or STABLE_TAG.fullmatch(latest_tag) is None
or refs is None
or releases is None
):
return (
[
violation(
"frontier_payload_invalid",
"$",
"stable latest release plus tag and release arrays",
{
"latest_release": type(latest_release).__name__,
"stable_refs": type(stable_refs_payload).__name__,
"releases": type(releases_payload).__name__,
},
FRONTIER_RULES,
)
],
identity,
)
stable_tags: set[str] = set()
for ref in refs:
if not isinstance(ref, dict):
return (
[
violation(
"frontier_payload_invalid",
"stable_refs",
"array of Git ref objects",
ref,
FRONTIER_RULES,
)
],
identity,
)
ref_name = ref.get("ref")
if isinstance(ref_name, str):
tag = ref_name.removeprefix("refs/tags/")
if STABLE_TAG.fullmatch(tag):
stable_tags.add(tag)
releases_by_tag: dict[str, dict[str, Any]] = {}
for release in releases:
if not isinstance(release, dict):
return (
[
violation(
"frontier_payload_invalid",
"releases",
"array of GitHub Release objects",
release,
FRONTIER_RULES,
)
],
identity,
)
release_tag = release.get("tag_name")
if isinstance(release_tag, str) and STABLE_TAG.fullmatch(release_tag):
releases_by_tag[release_tag] = release
latest_version = stable_version(latest_tag)
newer_tags = sorted(
(tag for tag in stable_tags if stable_version(tag) > latest_version),
key=stable_version,
)
orphaned = [tag for tag in newer_tags if tag not in releases_by_tag]
unadvertised = [
tag
for tag in newer_tags
if tag in releases_by_tag
and releases_by_tag[tag].get("draft") is False
and isinstance(releases_by_tag[tag].get("published_at"), str)
and bool(releases_by_tag[tag]["published_at"])
]
registry_tags: dict[str, set[str]] = {}
for registry in registry_payloads:
if (
not isinstance(registry, dict)
or not isinstance(registry.get("name"), str)
or not isinstance(registry.get("tags"), list)
or not all(isinstance(tag, str) for tag in registry["tags"])
):
return (
[
violation(
"frontier_payload_invalid",
"registries",
"array of registry tag-list objects",
registry,
FRONTIER_RULES,
)
],
identity,
)
registry_name = registry["name"]
for raw_tag in registry["tags"]:
tag = raw_tag if raw_tag.startswith("v") else f"v{raw_tag}"
if STABLE_TAG.fullmatch(tag) and stable_version(tag) > latest_version:
registry_tags.setdefault(tag, set()).add(registry_name)
identity.update(
{
"newer_stable_tags": ",".join(newer_tags),
"orphaned_stable_tags": ",".join(orphaned),
"unadvertised_published_stable_tags": ",".join(unadvertised),
"registry_stable_tags_beyond_latest": ",".join(
sorted(registry_tags, key=stable_version)
),
}
)
failures = [
violation(
"stable_tag_without_release",
f"refs/tags/{tag}",
"one GitHub Release object",
None,
FRONTIER_RULES,
)
for tag in orphaned
]
failures.extend(
violation(
"newer_stable_release_not_advertised",
f"releases/{tag}",
f"not newer than {latest_tag}",
tag,
FRONTIER_RULES,
)
for tag in unadvertised
)
failures.extend(
violation(
"registry_stable_tag_beyond_latest",
f"registries/{tag}",
f"no public stable container tag newer than {latest_tag}",
",".join(sorted(registry_tags[tag])),
FRONTIER_RULES,
)
for tag in sorted(registry_tags, key=stable_version)
)
return failures, identity
def activation_violations(
payload: Any, expected_release: dict[str, Any], activation_bytes: bytes
) -> list[Violation]:
@@ -541,6 +745,29 @@ def validate_activation(args: argparse.Namespace) -> int:
return 0
def validate_frontier(args: argparse.Namespace) -> int:
try:
latest_release = read_json(args.release_json)
stable_refs = read_json(args.stable_refs_json)
releases = read_json(args.releases_json)
registries = [read_json(path) for path in args.registry_tags_json]
except ValueError as exc:
failures = [
violation(
"frontier_payload_invalid", "$", "valid JSON inventories", str(exc), FRONTIER_RULES
)
]
identity: dict[str, Any] = {}
else:
failures, identity = frontier_violations(latest_release, stable_refs, releases, registries)
write_diagnostic(args.diagnostic, "stable_publication_frontier", identity, failures)
if failures:
report_failures(failures, FRONTIER_RULES)
return 1
return 0
def parse_args() -> argparse.Namespace:
parser = argparse.ArgumentParser(description=__doc__)
commands = parser.add_subparsers(dest="command", required=True)
@@ -555,6 +782,13 @@ def parse_args() -> argparse.Namespace:
activation.add_argument("--activation-json", type=Path, required=True)
activation.add_argument("--diagnostic", type=Path, required=True)
activation.add_argument("--github-output", type=Path, required=True)
frontier = commands.add_parser("frontier")
frontier.add_argument("--release-json", type=Path, required=True)
frontier.add_argument("--stable-refs-json", type=Path, required=True)
frontier.add_argument("--releases-json", type=Path, required=True)
frontier.add_argument("--registry-tags-json", type=Path, action="append", required=True)
frontier.add_argument("--diagnostic", type=Path, required=True)
return parser.parse_args()
@@ -562,7 +796,9 @@ def main() -> int:
args = parse_args()
if args.command == "release":
return validate_release(args)
return validate_activation(args)
if args.command == "activation":
return validate_activation(args)
return validate_frontier(args)
if __name__ == "__main__":
@@ -67,6 +67,9 @@ class ReleaseContinuityTest(unittest.TestCase):
command: str,
release: object,
activation: object | None = None,
stable_refs: object | None = None,
releases: object | None = None,
registries: list[object] | None = None,
) -> tuple[subprocess.CompletedProcess[str], dict[str, object], str]:
with tempfile.TemporaryDirectory() as directory:
root = Path(directory)
@@ -83,13 +86,32 @@ class ReleaseContinuityTest(unittest.TestCase):
str(release_path),
"--diagnostic",
str(diagnostic),
"--github-output",
str(output),
]
if command != "frontier":
args.extend(["--github-output", str(output)])
if command == "activation":
activation_path = root / "activation.json"
activation_path.write_bytes(encoded(activation))
args.extend(["--activation-json", str(activation_path)])
if command == "frontier":
stable_refs_path = root / "stable-refs.json"
releases_path = root / "releases.json"
stable_refs_path.write_text(json.dumps(stable_refs), encoding="utf-8")
releases_path.write_text(json.dumps(releases), encoding="utf-8")
args.extend(
[
"--stable-refs-json",
str(stable_refs_path),
"--releases-json",
str(releases_path),
]
)
for index, registry in enumerate(
registries or [{"name": "registry.example/pulse", "tags": []}]
):
registry_path = root / f"registry-{index}.json"
registry_path.write_text(json.dumps(registry), encoding="utf-8")
args.extend(["--registry-tags-json", str(registry_path)])
result = subprocess.run(
args,
cwd=ROOT,
@@ -272,6 +294,102 @@ class ReleaseContinuityTest(unittest.TestCase):
],
)
def test_frontier_accepts_tags_at_or_behind_advertised_release(self) -> None:
release = valid_release()
result, diagnostic, output = self.run_command(
"frontier",
release,
stable_refs=[
{"ref": "refs/tags/v6.4.1"},
{"ref": "refs/tags/v6.4.2"},
{"ref": "refs/tags/v6.4.3-rc.1"},
],
releases=[release],
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(diagnostic["status"], "success")
self.assertEqual(diagnostic["identity"]["newer_stable_tags"], "")
self.assertEqual(output, "")
def test_frontier_rejects_newer_stable_tag_without_release_packet(self) -> None:
release = valid_release()
result, diagnostic, _ = self.run_command(
"frontier",
release,
stable_refs=[[{"ref": "refs/tags/v6.4.2"}, {"ref": "refs/tags/v6.4.3"}]],
releases=[[release]],
)
self.assertEqual(result.returncode, 1)
self.assertEqual(
[item["code"] for item in diagnostic["violations"]],
["stable_tag_without_release"],
)
self.assertEqual(diagnostic["identity"]["orphaned_stable_tags"], "v6.4.3")
self.assertIn("orphaned version", result.stderr)
def test_frontier_rejects_public_registry_version_beyond_latest(self) -> None:
release = valid_release()
result, diagnostic, _ = self.run_command(
"frontier",
release,
stable_refs=[{"ref": "refs/tags/v6.4.2"}],
releases=[release],
registries=[
{
"name": "docker.io/rcourtman/pulse",
"tags": ["latest", "6.4", "6.4.2", "v6.4.3"],
},
{
"name": "ghcr.io/rcourtman/pulse",
"tags": ["v6.4.3", "6.4.3-rc.1"],
},
],
)
self.assertEqual(result.returncode, 1)
self.assertEqual(
[item["code"] for item in diagnostic["violations"]],
["registry_stable_tag_beyond_latest"],
)
self.assertEqual(
diagnostic["identity"]["registry_stable_tags_beyond_latest"],
"v6.4.3",
)
self.assertIn("docker.io/rcourtman/pulse", diagnostic["violations"][0]["actual"])
self.assertIn("ghcr.io/rcourtman/pulse", diagnostic["violations"][0]["actual"])
def test_frontier_rejects_published_stable_release_beyond_latest(self) -> None:
release = valid_release()
newer = {**release, "id": 67890, "tag_name": "v6.4.3"}
result, diagnostic, _ = self.run_command(
"frontier",
release,
stable_refs=[{"ref": "refs/tags/v6.4.3"}],
releases=[release, newer],
)
self.assertEqual(result.returncode, 1)
self.assertEqual(
[item["code"] for item in diagnostic["violations"]],
["newer_stable_release_not_advertised"],
)
def test_frontier_allows_in_progress_draft_beyond_latest(self) -> None:
release = valid_release()
draft = {
**release,
"id": 67890,
"tag_name": "v6.4.3",
"draft": True,
"published_at": None,
}
result, diagnostic, _ = self.run_command(
"frontier",
release,
stable_refs=[{"ref": "refs/tags/v6.4.3"}],
releases=[release, draft],
)
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(diagnostic["status"], "success")
if __name__ == "__main__":
unittest.main()