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
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:
@@ -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(
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user