fix(release): bind trusted builder to canonical purpose
git-diff-check git diff --check PASS on exact PR head
py-compile Python compileall PASS on active-runtime/app
reconciliation-contract Full source regression includes completed-replay/reconciliation contract PASS
secret-scan Diff-added lines secret scan PASS; no credential material
signer-validator-contract Signer contract suite PASS; live signer remains opt-in and no key was provisioned
campaign-approval-gate V2R2C2 trusted-controller source binding gate PASS; durable candidate creation remains post-merge
release-state-machine V2R2C2 release-controller source contract PASS; no production mutation enabled
autonomy-smoke-tests Source snapshot smoke/contract suite passed; production mutations disabled
autonomy-unit-tests 816 passed, 3 skipped, 154 subtests passed

This commit is contained in:
AIOS Governed Continuation
2026-08-29 15:25:31 +08:00
parent 8e90f317b3
commit 98bdeae6b4
5 changed files with 16 additions and 16 deletions
@@ -640,7 +640,7 @@ class TrustedCandidateBuilder:
"builder_key_id": self.signer.key_id,
"builder_key_generation": self.signer.key_generation,
"signature_algorithm": "Ed25519",
"signature_purpose": "builder_attestation",
"signature_purpose": "AIOS_TRUSTED_RELEASE_BUILDER",
"policy_sha256": self.config.policy_sha256,
"collector_ready": True,
"signer_ready": True,
@@ -659,7 +659,7 @@ class TrustedCandidateBuilder:
"builder_key_id": self.signer.key_id,
"builder_key_generation": self.signer.key_generation,
"signature_algorithm": "Ed25519",
"signature_purpose": "builder_attestation",
"signature_purpose": "AIOS_TRUSTED_RELEASE_BUILDER",
"source_commit": candidate["source_commit"], "tree_oid": candidate["tree_oid"],
"artifact_sha256": candidate["artifact_sha256"], "manifest_sha256": candidate["manifest_sha256"],
"package_closure_sha256": release_plan["deployment"]["package_closure_sha256"],
@@ -673,7 +673,7 @@ class TrustedCandidateBuilder:
}
canonical_attestation = _canonical_json(attestation)
fingerprint = hashlib.sha256(canonical_attestation).hexdigest()
signature = base64.b64encode(self.signer.sign_for_purpose("builder_attestation", canonical_attestation)).decode("ascii")
signature = base64.b64encode(self.signer.sign_for_purpose("AIOS_TRUSTED_RELEASE_BUILDER", canonical_attestation)).decode("ascii")
result = {
"schema": self.config.response_schema, "status": "BUILT", "recipe": recipe_name,
"repository": self.config.repository, "task_id": recipe["task_id"], "base_oid": recipe["base_oid"],
@@ -780,7 +780,7 @@ def _main() -> None:
keyring.signing_private_key_path,
key_id=os.environ["AIOS_TRUSTED_BUILDER_KEY_ID"],
key_generation=int(os.environ["AIOS_TRUSTED_BUILDER_KEY_GENERATION"]),
allowed_purpose="builder_attestation",
allowed_purpose="AIOS_TRUSTED_RELEASE_BUILDER",
)
listener = socket.fromfd(arguments.socket_fd, socket.AF_UNIX, socket.SOCK_STREAM)
collector = DeterministicEvidenceCollector(
@@ -42,7 +42,7 @@ from silent_release_controller import (
IDENTIFIER_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:-]{2,255}$")
NONCE_RE = re.compile(r"^[A-Za-z0-9][A-Za-z0-9_.:-]{15,255}$")
BUILDER_ATTESTATION_TRUST_DOMAIN = "aios.trusted-builder.attestation.v1"
BUILDER_ATTESTATION_PURPOSE = "builder_attestation"
BUILDER_ATTESTATION_PURPOSE = "AIOS_TRUSTED_RELEASE_BUILDER"
ALLOWED_CAPABILITIES = frozenset(
{
"runtime_switch",
@@ -26,7 +26,7 @@
"base_oid": "d2b5a8339a34a8f958a177f8a3b9e8296a57a7a6",
"candidate_id": "rc-v2r2c2-d2b5a8339a34",
"mode": "fixed",
"purpose": "release:candidate:trusted-build",
"purpose": "AIOS_TRUSTED_RELEASE_BUILDER",
"source_commit": "d2b5a8339a34a8f958a177f8a3b9e8296a57a7a6",
"task_id": "v12-durable-trusted-release-controller-activation-20260829",
"version": "V2R2C2"
@@ -34,7 +34,7 @@
"V2R2C3": {
"derives_from": "V2R2C2",
"mode": "governed-derived-only",
"purpose": "release:candidate:trusted-build",
"purpose": "AIOS_TRUSTED_RELEASE_BUILDER",
"version": "V2R2C3"
}
},
@@ -81,7 +81,7 @@ def _keyring_payload(private: Ed25519PrivateKey, *, purpose: str) -> dict:
}
payload = {
"algorithm": "Ed25519",
"purpose": "builder_attestation",
"purpose": "AIOS_TRUSTED_RELEASE_BUILDER",
"keys": [record],
}
payload["keyring_sha256"] = hashlib.sha256(
@@ -117,7 +117,7 @@ def _attestation(private: Ed25519PrivateKey) -> BuilderAttestation:
signature="",
builder_key_generation=1,
signature_algorithm="Ed25519",
signature_purpose="builder_attestation",
signature_purpose="AIOS_TRUSTED_RELEASE_BUILDER",
gitea_evidence_sha256=_canonical_digest(GITEA),
rollback_evidence_sha256=_canonical_digest({
"ready": True,
@@ -151,7 +151,7 @@ def test_builder_verifier_checks_domain_key_window_digest_and_signature(tmp_path
private = Ed25519PrivateKey.generate()
path = tmp_path / "builder-keyring.json"
path.write_text(
json.dumps(_keyring_payload(private, purpose="builder_attestation")),
json.dumps(_keyring_payload(private, purpose="AIOS_TRUSTED_RELEASE_BUILDER")),
encoding="utf-8",
)
verifier = BuilderAttestationVerifier(
@@ -178,7 +178,7 @@ def test_builder_verifier_checks_domain_key_window_digest_and_signature(tmp_path
@pytest.mark.parametrize("state", ["REVOKED", "EXPIRED", "FUTURE"])
def test_builder_verifier_rejects_unavailable_key_lifecycle_states(tmp_path, state):
private = Ed25519PrivateKey.generate()
payload = _keyring_payload(private, purpose="builder_attestation")
payload = _keyring_payload(private, purpose="AIOS_TRUSTED_RELEASE_BUILDER")
record = payload["keys"][0]
if state == "REVOKED":
record["status"] = "REVOKED"
@@ -203,7 +203,7 @@ def test_builder_verifier_rejects_unavailable_key_lifecycle_states(tmp_path, sta
def test_builder_verifier_rejects_unknown_key_invalid_signature_and_keyring_digest(tmp_path):
private = Ed25519PrivateKey.generate()
payload = _keyring_payload(private, purpose="builder_attestation")
payload = _keyring_payload(private, purpose="AIOS_TRUSTED_RELEASE_BUILDER")
path = tmp_path / "builder-keyring.json"
path.write_text(json.dumps(payload), encoding="utf-8")
verifier = BuilderAttestationVerifier(BuilderAttestationKeyRing.from_file(path))
@@ -252,7 +252,7 @@ def test_builder_keyring_rejects_attestation_metadata_mismatch(tmp_path, field,
private = Ed25519PrivateKey.generate()
path = tmp_path / "builder-keyring.json"
path.write_text(
json.dumps(_keyring_payload(private, purpose="builder_attestation")),
json.dumps(_keyring_payload(private, purpose="AIOS_TRUSTED_RELEASE_BUILDER")),
encoding="utf-8",
)
verifier = BuilderAttestationVerifier(
+3 -3
View File
@@ -173,7 +173,7 @@ def test_public_build_seam_accepts_only_the_fixed_v2r2c2_recipe_and_returns_serv
assert set(result["checks"]) == set(server.config.required_checks)
assert all(result["checks"].values())
assert result["attestation"]["trust_domain"] == "aios.trusted-builder.attestation.v1"
assert signer.calls and signer.calls[0][0] == "builder_attestation"
assert signer.calls and signer.calls[0][0] == "AIOS_TRUSTED_RELEASE_BUILDER"
assert result["attestation"]["fingerprint"] == hashlib.sha256(signer.calls[0][1]).hexdigest()
assert BuilderAttestation.from_dict(result["attestation"]).canonical_bytes() == signer.calls[0][1]
silent_bundle = result["silent_release_bundle"]
@@ -357,7 +357,7 @@ def test_backend_attestation_round_trip_verifies_with_production_keyring() -> No
key_generation = 1
def sign_for_purpose(self, purpose, payload):
assert purpose == "builder_attestation"
assert purpose == "AIOS_TRUSTED_RELEASE_BUILDER"
return private.sign(payload)
server, client, _ = make_seam(signer_override=Ed25519Signer())
@@ -380,7 +380,7 @@ def test_backend_attestation_round_trip_verifies_with_production_keyring() -> No
key_id="builder-key-001",
public_key=public_key,
algorithm="Ed25519",
purpose="builder_attestation",
purpose="AIOS_TRUSTED_RELEASE_BUILDER",
generation=1,
not_before="2020-01-01T00:00:00Z",
expires_at="2099-01-01T00:00:00Z",