mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
ef6e784c2e
Fresh stable readback still shows mutable v6.4.1 alongside orphan v6.4.2. Explain forward supersession without deleting historical tags or treating frontier success as release admission. Cover that distinction with a focused recovery regression; publication authority and all existing gates remain unchanged. Change-source: pulse-maintainer
448 lines
17 KiB
Python
448 lines
17 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from __future__ import annotations
|
|
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
import unittest
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
SCRIPT = ROOT / "scripts" / "release_control" / "release_continuity.py"
|
|
SOURCE_SHA = "a" * 40
|
|
DIGEST = "sha256:" + "b" * 64
|
|
|
|
|
|
def encoded(payload: object) -> bytes:
|
|
return json.dumps(payload).encode("utf-8")
|
|
|
|
|
|
def activation_asset(payload: object) -> dict[str, object]:
|
|
content = encoded(payload)
|
|
return {
|
|
"name": "release-activation.json",
|
|
"state": "uploaded",
|
|
"size": len(content),
|
|
"digest": "sha256:" + hashlib.sha256(content).hexdigest(),
|
|
}
|
|
|
|
|
|
def valid_release(activation: object | None = None) -> dict[str, object]:
|
|
if activation is None:
|
|
activation = valid_activation()
|
|
return {
|
|
"id": 12345,
|
|
"tag_name": "v6.4.2",
|
|
"target_commitish": SOURCE_SHA,
|
|
"draft": False,
|
|
"prerelease": False,
|
|
"immutable": True,
|
|
"published_at": "2026-08-31T17:00:00Z",
|
|
"assets": [activation_asset(activation)],
|
|
}
|
|
|
|
|
|
def valid_activation() -> dict[str, object]:
|
|
return {
|
|
"schema_version": 1,
|
|
"tag": "v6.4.2",
|
|
"release_id": "12345",
|
|
"target_commitish": SOURCE_SHA,
|
|
"source_release_run_id": "1001",
|
|
"convergence_run_id": "1002",
|
|
"r2_prefix": "releases/v6.4.2",
|
|
"server_image_digest": DIGEST,
|
|
"control_plane_image_digest": DIGEST,
|
|
"helm_chart_digest": DIGEST,
|
|
}
|
|
|
|
|
|
class ReleaseContinuityTest(unittest.TestCase):
|
|
def run_command(
|
|
self,
|
|
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)
|
|
release_path = root / "release.json"
|
|
release_path.write_text(json.dumps(release), encoding="utf-8")
|
|
diagnostic = root / "diagnostic.json"
|
|
output = root / "github-output"
|
|
output.touch()
|
|
args = [
|
|
sys.executable,
|
|
str(SCRIPT),
|
|
command,
|
|
"--release-json",
|
|
str(release_path),
|
|
"--diagnostic",
|
|
str(diagnostic),
|
|
]
|
|
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,
|
|
text=True,
|
|
capture_output=True,
|
|
check=False,
|
|
)
|
|
return (
|
|
result,
|
|
json.loads(diagnostic.read_text(encoding="utf-8")),
|
|
output.read_text(encoding="utf-8"),
|
|
)
|
|
|
|
def test_accepts_exact_immutable_stable_release(self) -> None:
|
|
result, diagnostic, output = self.run_command("release", valid_release())
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertEqual(diagnostic["status"], "success")
|
|
self.assertEqual(diagnostic["violations"], [])
|
|
self.assertIn("referenceable=true\n", output)
|
|
self.assertIn("tag=v6.4.2\n", output)
|
|
self.assertIn("release_id=12345\n", output)
|
|
self.assertIn(f"source_sha={SOURCE_SHA}\n", output)
|
|
|
|
def test_mutable_release_fails_with_one_actionable_reason(self) -> None:
|
|
release = valid_release()
|
|
release["immutable"] = False
|
|
result, diagnostic, output = self.run_command("release", release)
|
|
self.assertEqual(result.returncode, 1)
|
|
self.assertIn("referenceable=true\n", output)
|
|
self.assertIn("tag=v6.4.2\n", output)
|
|
self.assertIn("release_id=12345\n", output)
|
|
self.assertIn(f"source_sha={SOURCE_SHA}\n", output)
|
|
self.assertEqual(diagnostic["status"], "failure")
|
|
self.assertEqual(
|
|
[item["code"] for item in diagnostic["violations"]],
|
|
["release_mutable"],
|
|
)
|
|
self.assertIn("immutable=false", result.stderr)
|
|
self.assertIn("never repair the packet in place", result.stderr)
|
|
|
|
def test_reports_every_release_identity_violation(self) -> None:
|
|
result, diagnostic, output = self.run_command(
|
|
"release",
|
|
{
|
|
"id": True,
|
|
"tag_name": "v6.4.2-rc.1\nforged",
|
|
"target_commitish": "main",
|
|
"draft": True,
|
|
"prerelease": True,
|
|
"immutable": None,
|
|
"published_at": "",
|
|
},
|
|
)
|
|
self.assertEqual(result.returncode, 1)
|
|
self.assertEqual(output, "")
|
|
self.assertEqual(
|
|
{item["code"] for item in diagnostic["violations"]},
|
|
{
|
|
"release_id_invalid",
|
|
"stable_tag_invalid",
|
|
"source_identity_invalid",
|
|
"release_is_draft",
|
|
"release_is_prerelease",
|
|
"release_mutable",
|
|
"publication_time_invalid",
|
|
},
|
|
)
|
|
self.assertNotIn("forged", result.stderr)
|
|
|
|
def test_accepts_exact_activation_binding_and_emits_digests(self) -> None:
|
|
activation = valid_activation()
|
|
result, diagnostic, output = self.run_command(
|
|
"activation", valid_release(activation), activation
|
|
)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertEqual(diagnostic["status"], "success")
|
|
self.assertRegex(output, r"activation_sha256=[0-9a-f]{64}\n")
|
|
self.assertIn(f"server_image_digest={DIGEST}\n", output)
|
|
self.assertIn(f"control_plane_image_digest={DIGEST}\n", output)
|
|
self.assertIn(f"helm_chart_digest={DIGEST}\n", output)
|
|
|
|
def test_activation_mismatches_are_classified_without_outputs(self) -> None:
|
|
activation = valid_activation()
|
|
activation.update(
|
|
{
|
|
"schema_version": True,
|
|
"tag": "v6.4.1",
|
|
"release_id": 12345,
|
|
"target_commitish": "c" * 40,
|
|
"source_release_run_id": "",
|
|
"convergence_run_id": 1002,
|
|
"r2_prefix": "",
|
|
"server_image_digest": "latest",
|
|
"control_plane_image_digest": None,
|
|
"helm_chart_digest": "sha256:ABC",
|
|
}
|
|
)
|
|
result, diagnostic, output = self.run_command(
|
|
"activation", valid_release(activation), activation
|
|
)
|
|
self.assertEqual(result.returncode, 1)
|
|
self.assertEqual(output, "")
|
|
self.assertEqual(
|
|
{item["code"] for item in diagnostic["violations"]},
|
|
{
|
|
"activation_schema_invalid",
|
|
"activation_tag_mismatch",
|
|
"activation_release_mismatch",
|
|
"activation_source_mismatch",
|
|
"source_run_invalid",
|
|
"convergence_run_invalid",
|
|
"delivery_prefix_invalid",
|
|
"server_digest_invalid",
|
|
"control_plane_digest_invalid",
|
|
"helm_digest_invalid",
|
|
},
|
|
)
|
|
self.assertTrue(
|
|
all(
|
|
"publish a corrected replacement" in item["action"]
|
|
for item in diagnostic["violations"]
|
|
)
|
|
)
|
|
|
|
def test_mutable_release_does_not_hide_activation_damage(self) -> None:
|
|
activation = valid_activation()
|
|
del activation["server_image_digest"]
|
|
del activation["control_plane_image_digest"]
|
|
del activation["helm_chart_digest"]
|
|
release = valid_release(activation)
|
|
release["immutable"] = False
|
|
|
|
result, diagnostic, output = self.run_command(
|
|
"activation", release, activation
|
|
)
|
|
|
|
self.assertEqual(result.returncode, 1)
|
|
self.assertEqual(output, "")
|
|
self.assertEqual(
|
|
[item["code"] for item in diagnostic["violations"]],
|
|
[
|
|
"server_digest_invalid",
|
|
"control_plane_digest_invalid",
|
|
"helm_digest_invalid",
|
|
],
|
|
)
|
|
|
|
def test_activation_requires_one_digest_bound_release_asset(self) -> None:
|
|
activation = valid_activation()
|
|
release = valid_release(activation)
|
|
release["assets"] = []
|
|
|
|
result, diagnostic, output = self.run_command(
|
|
"activation", release, activation
|
|
)
|
|
|
|
self.assertEqual(result.returncode, 1)
|
|
self.assertEqual(output, "")
|
|
self.assertEqual(
|
|
[item["code"] for item in diagnostic["violations"]],
|
|
["activation_asset_invalid"],
|
|
)
|
|
|
|
def test_activation_rejects_download_that_differs_from_release_metadata(self) -> None:
|
|
expected = valid_activation()
|
|
downloaded = valid_activation()
|
|
downloaded["r2_prefix"] = "releases/v6.4.2-corrupted"
|
|
|
|
result, diagnostic, output = self.run_command(
|
|
"activation", valid_release(expected), downloaded
|
|
)
|
|
|
|
self.assertEqual(result.returncode, 1)
|
|
self.assertEqual(output, "")
|
|
self.assertEqual(
|
|
[item["code"] for item in diagnostic["violations"]],
|
|
[
|
|
"activation_asset_size_mismatch",
|
|
"activation_asset_digest_mismatch",
|
|
],
|
|
)
|
|
|
|
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_replacement_supersedes_orphan_without_granting_release_trust(self) -> None:
|
|
# Keep the same historical inventories across recovery. Deleting the
|
|
# orphan is neither necessary nor a substitute for release admission.
|
|
old = {**valid_release(), "tag_name": "v6.4.1", "immutable": False}
|
|
replacement = {**valid_release(), "tag_name": "v6.4.3"}
|
|
refs = [{"ref": "refs/tags/v6.4.2"}]
|
|
registries = [{"name": "ghcr.io/rcourtman/pulse", "tags": ["6.4.2"]}]
|
|
result, diagnostic, _ = self.run_command(
|
|
"frontier", old, stable_refs=refs, releases=[old],
|
|
registries=registries,
|
|
)
|
|
self.assertEqual(result.returncode, 1)
|
|
self.assertEqual(
|
|
{item["code"] for item in diagnostic["violations"]},
|
|
{"stable_tag_without_release", "registry_stable_tag_beyond_latest"},
|
|
)
|
|
for immutable in (False, True):
|
|
with self.subTest(immutable=immutable):
|
|
candidate = {**replacement, "immutable": immutable}
|
|
result, diagnostic, _ = self.run_command(
|
|
"frontier", candidate, stable_refs=refs,
|
|
releases=[old, candidate], registries=registries,
|
|
)
|
|
self.assertEqual(result.returncode, 0, result.stderr)
|
|
self.assertEqual(diagnostic["identity"]["orphaned_stable_tags"], "")
|
|
result, diagnostic, _ = self.run_command("release", candidate)
|
|
self.assertEqual(result.returncode, 0 if immutable else 1)
|
|
self.assertEqual(
|
|
[item["code"] for item in diagnostic["violations"]],
|
|
[] if immutable else ["release_mutable"],
|
|
)
|
|
|
|
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_checks_published_releases_without_a_matching_ref(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.2"}],
|
|
releases=[release, newer],
|
|
)
|
|
self.assertEqual(result.returncode, 1)
|
|
self.assertEqual(diagnostic["identity"]["newer_stable_tags"], "")
|
|
self.assertEqual(
|
|
diagnostic["identity"]["unadvertised_published_stable_tags"],
|
|
"v6.4.3",
|
|
)
|
|
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()
|