feat(autonomous-release): enforce four-source release closure
This commit is contained in:
+47
-10
@@ -1,35 +1,72 @@
|
||||
"""Release consistency gates before owner-approved deployment."""
|
||||
"""Read-only multi-source release consistency gate."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from dataclasses import dataclass
|
||||
|
||||
from .errors import ReleaseBlocked
|
||||
from .models import is_git_oid, is_sha256
|
||||
|
||||
|
||||
@dataclass(frozen=True, slots=True)
|
||||
class ReleaseEvidence:
|
||||
expected_version: str
|
||||
registry_version: str
|
||||
baseline_version: str
|
||||
local_tag_oid: str
|
||||
remote_tag_oid: str
|
||||
gitea_tag_oid: str
|
||||
expected_tag_oid: str
|
||||
local_peeled_target_oid: str
|
||||
remote_peeled_target_oid: str
|
||||
gitea_peeled_target_oid: str
|
||||
expected_target_oid: str
|
||||
artifact_sha256: str
|
||||
manifest_sha256: str
|
||||
evidence_sha256: str
|
||||
rollback_artifact_sha256: str
|
||||
|
||||
|
||||
class ReleaseGate:
|
||||
"""Require exact release consistency. Never mutates release state."""
|
||||
"""Require exact tag-object, peeled-target, version and package closure."""
|
||||
|
||||
def verify(self, evidence: ReleaseEvidence) -> None:
|
||||
if evidence.registry_version != evidence.baseline_version:
|
||||
raise ReleaseBlocked("VERSION_MISMATCH", "registry and baseline differ")
|
||||
versions = (
|
||||
evidence.expected_version,
|
||||
evidence.registry_version,
|
||||
evidence.baseline_version,
|
||||
)
|
||||
if not versions[0] or len(set(versions)) != 1:
|
||||
raise ReleaseBlocked("VERSION_MISMATCH", "expected, registry and baseline differ")
|
||||
tag_oids = (
|
||||
evidence.local_tag_oid,
|
||||
evidence.remote_tag_oid,
|
||||
evidence.gitea_tag_oid,
|
||||
evidence.expected_tag_oid,
|
||||
)
|
||||
if any(not is_git_oid(value) for value in tag_oids):
|
||||
raise ReleaseBlocked("TAG_OID_INVALID", "tag object OID is invalid")
|
||||
if evidence.local_tag_oid != evidence.remote_tag_oid:
|
||||
raise ReleaseBlocked("TAG_REMOTE_MISMATCH", "local and remote tags differ")
|
||||
raise ReleaseBlocked("TAG_REMOTE_MISMATCH", "local and remote tag objects differ")
|
||||
if evidence.remote_tag_oid != evidence.gitea_tag_oid:
|
||||
raise ReleaseBlocked("TAG_GITEA_MISMATCH", "Gitea tag differs from remote tag")
|
||||
if evidence.remote_tag_oid != evidence.expected_target_oid:
|
||||
raise ReleaseBlocked("TAG_TARGET_MISMATCH", "tag target differs from expected target")
|
||||
if len(evidence.artifact_sha256) != 64 or len(evidence.manifest_sha256) != 64:
|
||||
raise ReleaseBlocked("ARTIFACT_DIGEST_MISSING", "artifact closure is incomplete")
|
||||
raise ReleaseBlocked("TAG_GITEA_MISMATCH", "Gitea tag object differs")
|
||||
if evidence.gitea_tag_oid != evidence.expected_tag_oid:
|
||||
raise ReleaseBlocked("TAG_OBJECT_MISMATCH", "tag object differs from ReleasePlan")
|
||||
targets = (
|
||||
evidence.local_peeled_target_oid,
|
||||
evidence.remote_peeled_target_oid,
|
||||
evidence.gitea_peeled_target_oid,
|
||||
evidence.expected_target_oid,
|
||||
)
|
||||
if any(not is_git_oid(value) for value in targets):
|
||||
raise ReleaseBlocked("TAG_TARGET_OID_INVALID", "peeled target OID is invalid")
|
||||
if len(set(targets)) != 1:
|
||||
raise ReleaseBlocked("TAG_TARGET_MISMATCH", "peeled tag targets are not identical")
|
||||
digests = (
|
||||
evidence.artifact_sha256,
|
||||
evidence.manifest_sha256,
|
||||
evidence.evidence_sha256,
|
||||
evidence.rollback_artifact_sha256,
|
||||
)
|
||||
if any(not is_sha256(value) for value in digests):
|
||||
raise ReleaseBlocked("ARTIFACT_DIGEST_MISSING", "package closure is incomplete")
|
||||
|
||||
Reference in New Issue
Block a user