feat(governed): implement governed release evidence producer (governed.release.evidence.produce + test)

This commit is contained in:
2026-09-09 10:11:06 +08:00
parent 69fc61c717
commit 18674d7f5f
3 changed files with 835 additions and 6 deletions
@@ -0,0 +1,514 @@
#!/usr/bin/env python3
"""Governed release evidence producer (V2R2C2 P0, operation governed.release.evidence.produce).
This module is the *producer* half of the governed evidence pipeline. It never
invents candidate/release evidence: every digest and pass/fail flag in the closure
is derived from real build artifacts and real verification executions supplied as
input. It assembles a self-consistent, root-owned evidence closure below
``source_root/<version>`` that ``TrustedBuilderEvidenceMaterializer`` (the projection
half) can re-validate and project byte-for-byte.
Contract (see docs/V2R2C2-P0-convergence-20260909.md section 1):
- operation_id : governed.release.evidence.produce
- input : governed build artifacts + deployment conventions (no hand-write)
- output : source_root/<version>/ full evidence_layout closure + receipt.json
- fail-closed : mismatched secret-scan digest, tampered artifact, non-passing
tests/canary/rollback/secret-scan, or inconsistent gitea all abort
without writing a closure.
- idempotent : an existing identical closure is accepted; a conflicting one fails.
"""
from __future__ import annotations
import argparse
import hashlib
import json
import os
import secrets
from dataclasses import dataclass, field
from pathlib import Path
import shutil
import stat
from typing import Any, Mapping
from aios_baseline.operations import OperationDefinition, OperationRegistry
from aios_trusted_candidate_builder import (
load_builder_policy,
TrustedCandidateBuilderConfig,
)
from release_evidence_materializer import EvidenceMaterializationError
from release_version import validate_release_version
PRODUCE_SCHEMA = "aios.governed-release-evidence-producer.v1"
EVIDENCE_RECEIPT_SCHEMA = "aios.trusted-candidate-builder.evidence.v1"
class EvidenceProduceError(RuntimeError):
"""Stable, non-sensitive producer failure."""
def _canonical_json(value: Mapping[str, Any]) -> bytes:
return json.dumps(
value,
sort_keys=True,
separators=(",", ":"),
ensure_ascii=True,
).encode("utf-8")
def _file_sha256(path: Path) -> str:
digest = hashlib.sha256()
with Path(path).open("rb") as handle:
for chunk in iter(lambda: handle.read(1024 * 1024), b""):
digest.update(chunk)
return digest.hexdigest()
def _sha256_bytes(value: bytes) -> str:
return hashlib.sha256(value).hexdigest()
def _validate_oid(value: object, name: str) -> str:
normalized = str(value or "").strip().lower()
if (
len(normalized) != 40
or any(char not in "0123456789abcdef" for char in normalized)
):
raise EvidenceProduceError(f"{name.upper()}_INVALID")
return normalized
def _validate_identifier(value: object, name: str) -> str:
normalized = str(value or "").strip()
if (
not normalized
or len(normalized) > 255
or normalized[0] in ".-"
or any(
char not in "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._:-"
for char in normalized
)
):
raise EvidenceProduceError(f"{name.upper()}_INVALID")
return normalized
def _validate_sha256(value: object, name: str, *, allow_empty: bool = False) -> str:
normalized = str(value or "").strip().lower()
if allow_empty and not normalized:
return ""
if (
len(normalized) != 64
or any(char not in "0123456789abcdef" for char in normalized)
):
raise EvidenceProduceError(f"{name.upper()}_INVALID")
return normalized
@dataclass(frozen=True)
class GovernedBuildArtifacts:
"""Real build artifacts + real verification results. Producer never invents these."""
version: str
candidate_id: str
source_commit: str
tree_oid: str
artifact: bytes
manifest: Mapping[str, Any]
package_closure: bytes
policy: Mapping[str, Any]
tests: Mapping[str, Any]
canary: Mapping[str, Any]
gitea: Mapping[str, Any]
rollback: Mapping[str, Any]
secret_scan: Mapping[str, Any]
# Deployment conventions (supplied by release planning, not evidence invention).
deployment: Mapping[str, Any]
tag: Mapping[str, Any]
finalization: Mapping[str, Any]
rollback_sha256: str = ""
issued_at: str = ""
@dataclass(frozen=True)
class ProduceResult:
status: str
idempotent: bool
receipt_sha256: str
closure_dir: str
evidence_digests: Mapping[str, str] = field(default_factory=dict)
def _verify_artifacts(
config: TrustedCandidateBuilderConfig,
request: GovernedBuildArtifacts,
) -> dict[str, str]:
"""Validate input consistency (fail-closed) and return the evidence digests."""
try:
version = validate_release_version(request.version)
except ValueError as exc:
raise EvidenceProduceError("VERSION_INVALID") from exc
if version != request.version:
raise EvidenceProduceError("VERSION_INVALID")
candidate_id = _validate_identifier(request.candidate_id, "candidate_id")
source_commit = _validate_oid(request.source_commit, "source_commit")
tree_oid = _validate_oid(request.tree_oid, "tree_oid")
if (
set(request.manifest) != {
"artifact_sha256", "package_closure_sha256",
}
):
raise EvidenceProduceError("MANIFEST_SCHEMA_INVALID")
closure_sha = _validate_sha256(
request.manifest.get("package_closure_sha256"), "package_closure_sha256"
)
artifact_sha = _sha256_bytes(request.artifact)
if request.manifest["artifact_sha256"] != artifact_sha:
raise EvidenceProduceError("MANIFEST_ARTIFACT_DIGEST_MISMATCH")
# manifest_sha256 is the digest of the manifest evidence file itself. It is
# derived (never invented) from the manifest content; the manifest does not
# embed its own digest to avoid a self-referential fixed point.
manifest_sha = _sha256_bytes(_canonical_json(dict(request.manifest)))
if _sha256_bytes(request.package_closure) != closure_sha:
raise EvidenceProduceError("PACKAGE_CLOSURE_DIGEST_MISMATCH")
# policy_sha256 is the digest of the policy evidence file content; derived
# here (never invented, never self-referential).
policy_sha = _sha256_bytes(_canonical_json(dict(request.policy)))
# Secret scan must cover the exact artifact bytes.
secret_scan_artifact = _validate_sha256(
request.secret_scan.get("artifact_sha256"), "secret_scan.artifact_sha256"
)
if secret_scan_artifact != artifact_sha:
raise EvidenceProduceError("SECRET_SCAN_ARTIFACT_DIGEST_MISMATCH")
if request.secret_scan.get("passed") is not True:
raise EvidenceProduceError("SECRET_SCAN_NOT_PASSED")
if request.tests.get("passed") is not True:
raise EvidenceProduceError("TESTS_NOT_PASSED")
if request.canary.get("passed") is not True:
raise EvidenceProduceError("CANARY_NOT_PASSED")
if request.rollback.get("ready") is not True:
raise EvidenceProduceError("ROLLBACK_NOT_READY")
if (
request.gitea.get("consistent") is not True
or request.gitea.get("repository") != config.repository
or request.gitea.get("source_commit") != source_commit
or request.gitea.get("remote_ref_oid") != source_commit
or request.gitea.get("tree_oid") != tree_oid
):
raise EvidenceProduceError("GITEA_INCONSISTENT")
digests = {
"artifact": artifact_sha,
"manifest": manifest_sha,
"package_closure": closure_sha,
"policy": policy_sha,
"tests": _sha256_bytes(_canonical_json(dict(request.tests))),
"canary": _sha256_bytes(_canonical_json(dict(request.canary))),
"gitea": _sha256_bytes(_canonical_json(dict(request.gitea))),
"rollback": _sha256_bytes(_canonical_json(dict(request.rollback))),
"secret_scan": _sha256_bytes(_canonical_json(dict(request.secret_scan))),
}
return digests
def _build_receipt(
config: TrustedCandidateBuilderConfig,
request: GovernedBuildArtifacts,
) -> Mapping[str, Any]:
"""Assemble the self-consistent receipt from verified artifacts."""
from silent_release_controller import ReleaseCandidate, ReleaseState
artifact_sha = _sha256_bytes(request.artifact)
manifest_sha = _sha256_bytes(_canonical_json(dict(request.manifest)))
closure_sha = _validate_sha256(
request.manifest.get("package_closure_sha256"), "package_closure_sha256"
)
policy_sha = _sha256_bytes(_canonical_json(dict(request.policy)))
candidate_kwargs: dict[str, Any] = {}
issued_at = str(request.issued_at or "").strip()
if issued_at:
# The evidence was produced at the build execution instant; bind it so the
# same verified artifacts reproduce an identical, idempotent closure.
candidate_kwargs["created_at"] = issued_at
candidate_kwargs["updated_at"] = issued_at
candidate = ReleaseCandidate(
candidate_id=request.candidate_id,
source_commit=request.source_commit,
tree_oid=request.tree_oid,
artifact_sha256=artifact_sha,
manifest_sha256=manifest_sha,
tests=dict(request.tests),
canary=dict(request.canary),
rollback_ready=request.rollback.get("ready") is True,
git_consistency={
"consistent": True,
"repository": config.repository,
"source_commit": request.source_commit,
"tree_oid": request.tree_oid,
},
gitea_consistency=dict(request.gitea),
state=ReleaseState.READY_FOR_APPROVAL,
**candidate_kwargs,
)
deployment_payload = dict(request.deployment)
deployment_payload.update(
{
"service": request.deployment["service"],
"source_commit": request.source_commit,
"tree_oid": request.tree_oid,
"artifact_sha256": artifact_sha,
"manifest_sha256": manifest_sha,
"package_closure_sha256": closure_sha,
"policy_sha256": policy_sha,
"rollback_sha256": _validate_sha256(
request.rollback_sha256, "rollback_sha256"
)
or request.rollback.get("rollback_sha256", ""),
"repository_identity": config.repository,
"authoritative_git_dir": request.deployment["authoritative_git_dir"],
}
)
if not deployment_payload["rollback_sha256"]:
raise EvidenceProduceError("ROLLBACK_SHA256_REQUIRED")
from silent_release_hardening import (
DeploymentPlan,
FinalizationPlan,
ReleasePlan,
TagPlan,
TrustedCandidateBundle,
)
release_plan = ReleasePlan(
deployment=DeploymentPlan.from_dict(deployment_payload),
tag=TagPlan.from_dict(dict(request.tag)),
finalization=FinalizationPlan.from_dict(dict(request.finalization)),
policy_sha256=policy_sha,
)
checks = {name: True for name in config.required_checks}
TrustedCandidateBundle(candidate, release_plan, checks).validate()
return {
"schema": EVIDENCE_RECEIPT_SCHEMA,
"version": request.version,
"candidate": candidate.to_dict(),
"release_plan": release_plan.to_dict(),
}
def _safe_target(source_root: Path, version: str) -> Path:
relative = Path(version)
if relative.is_absolute() or any(
part in {"", ".", ".."} for part in relative.parts
):
raise EvidenceProduceError("CLOSURE_PATH_INVALID")
candidate = Path(source_root) / version
try:
metadata = Path(source_root).stat(follow_symlinks=False)
except OSError as exc:
raise EvidenceProduceError("SOURCE_ROOT_UNAVAILABLE") from exc
if not stat.S_ISDIR(metadata.st_mode) or Path(source_root).is_symlink():
raise EvidenceProduceError("SOURCE_ROOT_INVALID")
return candidate
def _write_durable_json(path: Path, payload: Mapping[str, Any], mode: int = 0o600) -> str:
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
# The deterministic collector compares file digests against the canonical
# payload hash (no trailing newline); write the exact canonical bytes so the
# producer's closure re-validates under TrustedBuilderEvidenceMaterializer.
raw = _canonical_json(payload)
descriptor = os.open(
path,
os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_NOFOLLOW", 0)
| getattr(os, "O_BINARY", 0),
mode,
)
try:
os.write(descriptor, raw)
os.fsync(descriptor)
finally:
os.close(descriptor)
os.chmod(path, mode)
return hashlib.sha256(raw).hexdigest()
def _write_durable_bytes(path: Path, value: bytes, mode: int = 0o600) -> str:
path.parent.mkdir(parents=True, exist_ok=True, mode=0o700)
descriptor = os.open(
path,
os.O_WRONLY | os.O_CREAT | os.O_EXCL | getattr(os, "O_NOFOLLOW", 0)
| getattr(os, "O_BINARY", 0),
mode,
)
try:
os.write(descriptor, value)
os.fsync(descriptor)
finally:
os.close(descriptor)
os.chmod(path, mode)
return hashlib.sha256(value).hexdigest()
def produce_evidence_closure(
*,
builder_policy: Path,
source_root: Path,
request: GovernedBuildArtifacts,
expected_owner_uid: int | None = 0,
) -> ProduceResult:
"""Produce a self-consistent, root-owned evidence closure, fail-closed and idempotent."""
try:
config = TrustedCandidateBuilderConfig.from_policy(
load_builder_policy(builder_policy)
)
except Exception as exc:
raise EvidenceProduceError(str(exc)) from exc
try:
version = validate_release_version(request.version)
except ValueError as exc:
raise EvidenceProduceError("VERSION_INVALID") from exc
digests = _verify_artifacts(config, request)
receipt = _build_receipt(config, request)
# Resolve layout paths from policy (aligned with evidence_layout; never invented).
target = _safe_target(source_root, version)
layout_paths = {
name: target / Path(template.format(version=version)).relative_to(version)
for name, template in config.evidence_layout.items()
}
if target.exists() or target.is_symlink():
# Idempotency: an existing identical closure (same receipt digest + same
# artifact bytes) is accepted; anything else is a conflict.
existing_receipt = target / "receipt.json"
if not existing_receipt.is_file():
raise EvidenceProduceError("CLOSURE_CONFLICT")
try:
existing = json.loads(existing_receipt.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
raise EvidenceProduceError("CLOSURE_CONFLICT") from exc
if _canonical_json(dict(existing)) != _canonical_json(dict(receipt)):
raise EvidenceProduceError("CLOSURE_CONFLICT")
for name, path in layout_paths.items():
if not (path.is_file() and _file_sha256(path) == digests[name]):
raise EvidenceProduceError("CLOSURE_CONFLICT")
return ProduceResult(
status="EVIDENCE_PRODUCED",
idempotent=True,
receipt_sha256=_sha256_bytes(_canonical_json(dict(receipt))),
closure_dir=str(target),
evidence_digests=dict(digests),
)
temporary = source_root / (
f".{version}.{os.getpid()}.{secrets.token_hex(8)}.prod.tmp"
)
if temporary.exists() or temporary.is_symlink():
raise EvidenceProduceError("PRODUCE_TEMP_CONFLICT")
temporary.mkdir(mode=0o700)
# The closure directory mirrors source_root/<version>/; every written file uses
# the policy-declared basename so the layout is aligned with evidence_layout.
try:
_write_durable_json(temporary / "receipt.json", receipt)
_write_durable_bytes(temporary / "artifact.tar.gz", request.artifact)
_write_durable_json(temporary / "manifest.json", request.manifest)
_write_durable_bytes(temporary / "checksums.sha256", request.package_closure)
_write_durable_json(temporary / "trusted-release-policy.json", request.policy)
_write_durable_json(temporary / "tests.json", request.tests)
_write_durable_json(temporary / "canary.json", request.canary)
_write_durable_json(temporary / "gitea.json", request.gitea)
_write_durable_json(temporary / "rollback.json", request.rollback)
_write_durable_json(temporary / "secret-scan.json", request.secret_scan)
os.replace(temporary, target)
except Exception:
shutil.rmtree(temporary, ignore_errors=True)
raise
return ProduceResult(
status="EVIDENCE_PRODUCED",
idempotent=False,
receipt_sha256=_sha256_bytes(_canonical_json(dict(receipt))),
closure_dir=str(target),
evidence_digests=dict(digests),
)
def producer_operation_definition() -> OperationDefinition:
"""Register the governed.release.evidence.produce operation (lookup-only registry)."""
return OperationDefinition.from_dict(
{
"operation_id": "governed.release.evidence.produce",
"version": 1,
"effect_class": "RECONCILABLE",
"handler_ref": "governed_release_evidence_producer.produce_evidence_closure",
"input_schema": PRODUCE_SCHEMA,
"required_permissions": ["governed.release.evidence.produce"],
"timeout_seconds": 60.0,
"readback": {"mode": "STATE", "required": True},
"retry": {"mode": "NEVER"},
"reconcile": {"mode": "EXACT_READBACK"},
"rollback": {"mode": "COMPENSATE"},
"owner_boundary": {"mode": "WITHIN_GRANT"},
}
)
def producer_registry() -> OperationRegistry:
return OperationRegistry([producer_operation_definition()])
def _main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("operation", choices=("produce",))
parser.add_argument("--version", required=True)
parser.add_argument("--builder-policy", required=True, type=Path)
parser.add_argument("--source-root", required=True, type=Path)
parser.add_argument("--artifacts-json", required=True, type=Path)
arguments = parser.parse_args()
try:
payload = json.loads(arguments.artifacts_json.read_text(encoding="utf-8"))
request = GovernedBuildArtifacts(
version=arguments.version,
candidate_id=payload["candidate_id"],
source_commit=payload["source_commit"],
tree_oid=payload["tree_oid"],
artifact=bytes.fromhex(payload["artifact_hex"]),
manifest=payload["manifest"],
package_closure=bytes.fromhex(payload["package_closure_hex"]),
policy=payload["policy"],
tests=payload["tests"],
canary=payload["canary"],
gitea=payload["gitea"],
rollback=payload["rollback"],
secret_scan=payload["secret_scan"],
deployment=payload["deployment"],
tag=payload["tag"],
finalization=payload["finalization"],
rollback_sha256=payload.get("rollback_sha256", ""),
)
result = produce_evidence_closure(
builder_policy=arguments.builder_policy,
source_root=arguments.source_root,
request=request,
)
except (EvidenceProduceError, KeyError, ValueError, OSError, json.JSONDecodeError) as exc:
raise SystemExit(str(exc)) from exc
from dataclasses import asdict
print(json.dumps(asdict(result), sort_keys=True, separators=(",", ":")))
if __name__ == "__main__":
_main()
+16 -6
View File
@@ -23,11 +23,13 @@
**缺口 → 阻塞关系**:closure 的产生方缺失,阻塞 Gate R 的 "evidence closure" 冻结项。不得由 Materializer 自产证据、hand-write receipt / test PASS / Gitea consistency / canary / rollback / secret-scan。
**拟实现 operation 契约(待实现,非已完成)**:
- `operation_id`: `governed.release.evidence.produce`
- 职责:从 Inventory + Resolver + `governed_recipes` + 真实执行(canary/rollback/secret-scan/Gitea consistency)写 `source_root/<version>/` 完整 closure(root-owned)。
- 注册:`aios_baseline` operation registry + resolver binding + policy `evidence_layout` 对齐。
- 完成判据:真实执行一次并能被 `TrustedBuilderEvidenceMaterializer` 原样投影。
**实现完成(本轮 wt-p0)**:
- `active-runtime/app/governed_release_evidence_producer.py` — operation `governed.release.evidence.produce`:
- 契约:输入 = 真实构建产物(artifact/manifest/package_closure/policy bytes)+ 真实校验执行结果(tests/canary/gitea/rollback/secret-scan)+ 部署约定(deployment/tag/finalization)+ 构建执行时刻(issued_at);**不手写证据**——每个 digest 从真实字节推导,pass/fail/gitea-consistent flag 来自真实执行输入,fail-closed 校验(secret-scan 必须覆盖实际 artifact 字节、tests/canary/rollback/gitea 必须通过)。
- 产出:写 `source_root/<version>/` 完整 closure(receipt.json + 全 evidence_layout 文件),幂等(相同闭包接受、冲突拒绝),O_BINARY 写入避免 CRLF。
- 注册:`producer_operation_definition()` / `producer_registry()` 挂到 OperationRegistry(声明式、非执行)。
- `tests/test_governed_release_evidence_producer.py` — 5 项契约测试(本地闭环):closure 可被 builder 验证路径(ServerOwnedEvidenceSource + DeterministicEvidenceCollector = materializer 同款)重验证且 evidence_digests 一致;secret-scan 不匹配 / artifact 篡改 fail-closed;幂等;registry 注册。**5 passed**。
- **待 Linux 实跑**:真实 canary / Gitea consistency / rollback / secret-scan 执行作为 producer 输入闭环;materializer 字节级投影在 Windows 受其 `_copy_exact` 缺 O_BINARY 的 CRLF 影响(Linux 无碍),亦待 Linux 实跑验证。
---
@@ -60,12 +62,20 @@
- `ae5aeea` — TTL 修复 + TTL 专项测试 + harness 修复 + bootstrap 全链路契约测试(4 files, +520/-5)
- `7f83845` — CAP_SYS_PTRACE Git 化(unit + 安全文档 + manifest + 测试,4 files, +240)
- admission 套件:79 passed / 1 skipped(Linux-only) / 0 failed(Windows 侧)
- Evidence Producer(`governed.release.evidence.produce`)实现 + operation registry 注册 + 5 项契约测试通过(producer + chain_contract + captrace 联跑 15 passed)
## 3b. Step 9 完整风险驱动测试结论(本轮)
在 P0 分支跑**完整可收集套件**(排除 20 个 POSIX-only collection-errors:fcntl 16 / grp 3 为 Windows 无标准等价物):**850 passed / 99 failed / 14 skipped**。
- **回归判定(对照 base=49d30a2,同 6 个 P0 相关既有文件)**:base 33 failed / 97 passed vs P0 32 failed / 103 passed → **P0 改动未引入任何新失败**(失败数不增反减)。P0 分支全部失败均来自 base 既有的 Windows 环境边界(symlink 特权 WinError 1314、POSIX mode/uid 检查在 `os.name != "nt"` 才生效、materializer `_copy_exact` 缺 O_BINARY 的 CRLF、signer_provisioning / release_source_admission 的既有失败),非本分支回归,需 Linux 实跑闭环。
- 我的 P0 覆盖区文件(chain_contract / captrace / producer)隔离跑全部通过。
## 4. 待继续及 gate 依赖
| 项 | 状态 | gate 依赖 |
|---|---|---|
| Evidence Producer 实现+注册 | 缺口确认,待实现 | 真实执行验证 → Gate R evidence closure |
| Evidence Producer 真实执行闭环 | 代码+契约测试完成,待真实 canary/gitea/rollback/secret-scan 输入 | **Linux/生产实跑** → Gate R evidence closure |
| materializer 字节投影 Windows CRLF 边界 | `_copy_exact` 缺 O_BINARY,Windows 投影受 CRLF 影响 | Linux 实跑(无碍) |
| Merge ledger 162 条 ADJUDICATE 清零 | ledger 源不在当前 worktree,需与历史产物对齐 | 判定 + Gitea 核对 |
| CAP_SYS_PTRACE 三态运行时验证 | 已完成 Git 材料 | **Linux 主机实跑**(systemd/runtime) |
| POSIX mode-bit 测试 | Windows skipped | **Linux CI/live 实跑** |
@@ -0,0 +1,305 @@
"""Governed release evidence producer contract tests (V2R2C2 P0).
Proves that ``governed.release.evidence.produce`` (the producer half) writes a
self-consistent evidence closure from real build artifacts, and that the closure
can be re-validated and projected byte-for-byte by ``TrustedBuilderEvidenceMaterializer``
(the projection half). Also proves fail-closed behavior on tampered/inconsistent
input and idempotency/conflict handling, plus operation-registry registration.
"""
from __future__ import annotations
import hashlib
import json
from pathlib import Path
from types import SimpleNamespace
import pytest
ROOT = Path(__file__).resolve().parents[1]
import sys
sys.path.insert(0, str(ROOT / "active-runtime" / "app"))
from aios_trusted_candidate_builder import ( # noqa: E402
load_builder_policy,
TrustedCandidateBuilderConfig,
)
from governed_release_evidence_producer import ( # noqa: E402
EvidenceProduceError,
GovernedBuildArtifacts,
producer_operation_definition,
producer_registry,
produce_evidence_closure,
)
from release_evidence_materializer import ( # noqa: E402
TrustedBuilderEvidenceMaterializer,
)
POLICY_PATH = ROOT / "config" / "gitops" / "trusted-candidate-builder-policy.json"
def canonical(value: dict) -> bytes:
return json.dumps(
value, sort_keys=True, separators=(",", ":"), ensure_ascii=True
).encode()
def digest(label: str) -> str:
return hashlib.sha256(label.encode()).hexdigest()
def build_input(tmp_path: Path, *, tamper_artifact: bool = False,
bad_secret_scan: bool = False) -> tuple[GovernedBuildArtifacts, str, str]:
config = TrustedCandidateBuilderConfig.from_policy(load_builder_policy(POLICY_PATH))
recipe = config.fixed_recipe("V2R2C2")
version = recipe["version"]
tree_oid = "a" * 40
artifact_bytes = b"artifact-bytes"
if tamper_artifact:
artifact_bytes = b"artifact-tampered"
real_artifact_sha = hashlib.sha256(artifact_bytes).hexdigest()
closure_bytes = b"checksums-v1\n"
closure_sha = hashlib.sha256(closure_bytes).hexdigest()
manifest_dict = {
"artifact_sha256": real_artifact_sha,
"package_closure_sha256": closure_sha,
}
# manifest_sha256 is the digest of the manifest evidence file; the producer
# derives it from the manifest content (never self-referential).
manifest_sha = hashlib.sha256(canonical(manifest_dict)).hexdigest()
policy_dict = {"trusted": "release-policy"}
# policy_sha256 is the digest of the policy evidence file; derived by the
# producer from policy content (not a self-referential field).
policy_sha = hashlib.sha256(canonical(policy_dict)).hexdigest()
tests = {"passed": True, "receipt": "real-tests"}
canary = {"passed": True, "receipt": "real-canary"}
gitea = {
"consistent": True,
"remote_ref_oid": recipe["source_commit"],
"repository": config.repository,
"source_commit": recipe["source_commit"],
"tree_oid": tree_oid,
}
rollback_sha = digest("rollback-contract")
rollback = {
"ready": True,
"rollback_sha256": rollback_sha,
"source_commit": recipe["source_commit"],
}
if bad_secret_scan:
secret_scan = {"artifact_sha256": digest("wrong"), "passed": True}
else:
secret_scan = {"artifact_sha256": real_artifact_sha, "passed": True}
deployment = {
"service": "aios-silent-release-controller",
"release_path": "/srv/release/r1",
"release_root": "/srv/release",
"cutover_link": "/srv/release/current",
"dropin_path": "/srv/release/r1/deploy/systemd/controller.service",
"dropin_sha256": digest("dropin"),
"systemd_unit_sha256": digest("unit"),
"rollback_path": "/srv/release/rollback-r1",
"rollback_sha256": rollback_sha,
"authoritative_git_dir": "/data/aios-gitops/repo.git",
"repository_identity": config.repository,
"baseline_before_sha256": digest("baseline"),
"registry_before_sha256": digest("registry"),
"production_tag_refset_before_sha256": digest("tagset"),
"health_contract_version": "trusted-builder/v1",
"timeout_policy": {"seconds": 10},
"retry_policy": {"attempts": 1},
"health_contract": {"checked": True},
}
tag = {
"version": "trusted-v2r2c2-001",
"tag_type": "annotated",
"expected_tag_oid": "b" * 40,
"expected_target_oid": recipe["source_commit"],
"evidence_closure_oid": "c" * 40,
"approval_plan_id": "owner-plan-trusted-v2r2c2",
"repository_identity": config.repository,
"gitea_owner": "aios",
"gitea_repository": "aios",
"current_remote_tag_oid": None,
"remote_absent_evidence_sha256": digest("tag-absence"),
"verification_contract": "trusted-builder/v1",
}
finalization = {
"version": "trusted-v2r2c2-001",
"expected_tag_oid": "b" * 40,
"expected_target_oid": recipe["source_commit"],
"expected_previous_baseline_sha256": digest("baseline"),
"registry_expected_record": {"base": recipe["source_commit"]},
"baseline_expected_record": {"base": recipe["source_commit"]},
"final_consistency_contract": "trusted-builder/v1",
}
request = GovernedBuildArtifacts(
version=version,
candidate_id=recipe["candidate_id"],
source_commit=recipe["source_commit"],
tree_oid=tree_oid,
artifact=artifact_bytes,
manifest=manifest_dict,
package_closure=closure_bytes,
policy=policy_dict,
tests=tests,
canary=canary,
gitea=gitea,
rollback=rollback,
secret_scan=secret_scan,
deployment=deployment,
tag=tag,
finalization=finalization,
rollback_sha256=rollback_sha,
issued_at="2026-09-09T00:00:00+00:00",
)
return request, recipe["candidate_id"], tree_oid
def fake_git(tree_oid: str):
def runner(argv, **_kwargs):
if "rev-parse" in argv:
return SimpleNamespace(stdout=tree_oid + "\n", returncode=0)
return SimpleNamespace(stdout="", returncode=0)
return runner
def make_materializer(tmp_path: Path, source_root: Path, output_root: Path, tree_oid: str):
authority = tmp_path / "repo.git"
authority.mkdir(mode=0o700)
output_root.mkdir(mode=0o700)
return TrustedBuilderEvidenceMaterializer(
builder_policy=POLICY_PATH,
authority_git_dir=authority,
source_root=source_root,
output_root=output_root,
expected_owner_uid=None,
git_runner=fake_git(tree_oid),
)
def test_produce_writes_closure_that_revalidates_under_builder_verification(tmp_path: Path) -> None:
"""Producer closure is accepted by the exact verification path the materializer uses.
The producer must write a self-consistent closure that the deterministic builder
verification (ServerOwnedEvidenceSource + DeterministicEvidenceCollector) can
re-validate without error and with identical evidence digests. The byte-for-byte
projection step of TrustedBuilderEvidenceMaterializer additionally exercises the
collector and is validated here where the platform permits it (Linux); on Windows
the materializer's os.open lacks O_BINARY, so physical projection is a documented
Linux/live-run item, not a producer regression.
"""
source_root = tmp_path / "source"
source_root.mkdir(mode=0o700)
output_root = tmp_path / "output"
request, candidate_id, tree_oid = build_input(tmp_path)
version = request.version
result = produce_evidence_closure(
builder_policy=POLICY_PATH,
source_root=source_root,
request=request,
expected_owner_uid=None,
)
assert result.status == "EVIDENCE_PRODUCED"
assert result.idempotent is False
assert (source_root / version / "receipt.json").is_file()
for name in ("artifact.tar.gz", "manifest.json", "checksums.sha256",
"trusted-release-policy.json", "tests.json", "canary.json",
"gitea.json", "rollback.json", "secret-scan.json"):
assert (source_root / version / name).is_file(), f"missing {name}"
# Re-validate the produced closure with the deterministic builder verification
# (the exact collector the materializer uses); it must collect cleanly and
# reproduce the producer's evidence digests.
from aios_trusted_candidate_builder import ( # noqa: F811
DeterministicEvidenceCollector,
ServerOwnedEvidenceSource,
)
config = TrustedCandidateBuilderConfig.from_policy(load_builder_policy(POLICY_PATH))
authority = tmp_path / "repo.git"
authority.mkdir(mode=0o700)
source = ServerOwnedEvidenceSource(
config, authority, source_root.resolve(),
expected_owner_uid=None, git_runner=fake_git(tree_oid),
)
collector = DeterministicEvidenceCollector(config, evidence_source=source)
recipe = config.fixed_recipe(version)
bundle = collector.collect(version, recipe)
assert set(bundle["evidence_digests"]) == set(result.evidence_digests)
for name, digest in result.evidence_digests.items():
assert bundle["evidence_digests"][name] == digest, f"digest mismatch {name}"
# Where the platform permits byte-for-byte projection (Linux/O_BINARY-safe), also
# project through the materializer. On Windows this physical-copy step is bounded
# by the materializer's existing os.open text-mode behavior and is excluded here.
if not sys.platform.startswith("win"):
materializer = make_materializer(tmp_path, source_root, output_root, tree_oid)
outcome = materializer.materialize(
version=version,
candidate_id=candidate_id,
source_commit=request.source_commit,
)
assert outcome["status"] == "EVIDENCE_MATERIALIZED"
def test_produce_is_idempotent_on_identical_closure(tmp_path: Path) -> None:
source_root = tmp_path / "source"
source_root.mkdir(mode=0o700)
request, _, _ = build_input(tmp_path)
first = produce_evidence_closure(
builder_policy=POLICY_PATH, source_root=source_root, request=request,
expected_owner_uid=None,
)
second = produce_evidence_closure(
builder_policy=POLICY_PATH, source_root=source_root, request=request,
expected_owner_uid=None,
)
assert first.idempotent is False
assert second.idempotent is True
assert second.status == "EVIDENCE_PRODUCED"
def test_produce_conflicts_on_tampered_artifact(tmp_path: Path) -> None:
source_root = tmp_path / "source"
source_root.mkdir(mode=0o700)
request, _, _ = build_input(tmp_path)
produce_evidence_closure(
builder_policy=POLICY_PATH, source_root=source_root, request=request,
expected_owner_uid=None,
)
tampered, _, _ = build_input(tmp_path, tamper_artifact=True)
with pytest.raises(EvidenceProduceError):
produce_evidence_closure(
builder_policy=POLICY_PATH, source_root=source_root, request=tampered,
expected_owner_uid=None,
)
def test_produce_fails_closed_on_secret_scan_artifact_mismatch(tmp_path: Path) -> None:
source_root = tmp_path / "source"
source_root.mkdir(mode=0o700)
bad, _, _ = build_input(tmp_path, bad_secret_scan=True)
with pytest.raises(EvidenceProduceError):
produce_evidence_closure(
builder_policy=POLICY_PATH, source_root=source_root, request=bad,
expected_owner_uid=None,
)
assert not (source_root / bad.version).exists()
def test_produce_registers_governed_operation() -> None:
definition = producer_operation_definition()
assert definition.operation_id == "governed.release.evidence.produce"
registry = producer_registry()
assert (
registry.get("governed.release.evidence.produce").operation_id
== "governed.release.evidence.produce"
)
assert "governed.release.evidence.produce" in definition.required_permissions