Files
aios/scripts/round3_provider_gatew_prove_v2.py
T
owner c8ea953acd feat(governed): finalize Round-3 Gate-W Finalizer v2 — real git-transport Gitea provider + append-only receipts + separated Gate semantics (V2R2C2 P0)
Finalizer v2 lands three audit fixes:
- Gitea consistency proven via authoritative git transport (remote get-url /
  symbolic-ref --quiet HEAD / ls-remote --exit-code origin <exact branch>);
  receipt records transport=git-ls-remote, api_verified=false (no REST invented).
- Receipts are append-only immutable: each run uses its own
  round3-gate-w/<source[:12]>/<run-id>/<kind>.json namespace; existing ref fails
  closed (GITEA_PROVIDER_RECEIPT_EXISTS, O_EXCL+O_NOFOLLOW root-owned).
- Gate semantics separated: provider_auth_closed / tests_result_passed /
  secret_scan_result_passed / gitea_consistent / gate_w_ready independent;
  authentication PASS never converts a red result gate into Gate-W PASS.

New files: active-runtime/app/gitea_transport_consistency_provider.py,
scripts/round3_provider_gatew_prove_v2.py (replaces prove v1),
tests/test_gitea_transport_consistency_provider.py.
prove v2 enforces a real clean git checkout (HEAD==source, tree, clean) and
returns RC 0/1/2/3. Finalizer zip SHA256=c5f031967a7359b89398eccacb68c07162d92e1c5b2c5f4badf1a669c9f31ef6 (manifest verified).

Three prior tests failures resolved without changing assertions or adding
allowlist: V2R1C6 digest + rollback = CRLF/tar-export contamination false
failures (LF normalize reproduces exact hash; sh returns 42+BLOCKED); signer
self-test = real deployment config (allowed_signers pubkey synced to actual
credential, SIGNER_SELF_TEST=PASS rc=0).

This final source commit is FINAL_SOURCE_HEAD; subsequent commits on source
branch are prohibited (package goes to artifact store / detached).
2026-09-09 15:51:18 +08:00

155 lines
5.9 KiB
Python

#!/usr/bin/env python3
"""Round-3 Gate-W proof using immutable, append-only provider receipts.
Requires a REAL clean Git checkout at FINAL_SOURCE_HEAD. It never deletes or
overwrites old receipts. Each run writes a new namespace.
It distinguishes three dimensions:
* provider authentication closure,
* provider result gates (e.g. tests passed),
* overall Gate-W readiness.
A resolver PASS never converts ``tests.result.passed=false`` into Gate-W PASS.
"""
from __future__ import annotations
import argparse
from datetime import datetime, timezone
import json
import os
from pathlib import Path
import subprocess
import sys
_APP = Path(__file__).resolve().parents[1] / "active-runtime" / "app"
sys.path.insert(0, str(_APP))
from gitea_transport_consistency_provider import produce_gitea_consistency_receipt
from trusted_evidence_providers import TrustedProviderExecutionError, _validate_oid, produce
from trusted_provider_receipts import TrustedProviderPolicy, TrustedProviderReceiptResolver
GATE_W = ("tests", "secret_scan", "gitea")
def mode(v):
return v if isinstance(v, int) else int(str(v), 8)
def build_resolver(policy_path):
raw = json.loads(Path(policy_path).read_text(encoding="utf-8"))
defaults = dict(raw.get("defaults") or {})
policies = {}
for name,cfg in dict(raw.get("providers") or {}).items():
policies[name] = TrustedProviderPolicy(
evidence_kind=name,
provider_identity=str(cfg["provider_identity"]),
store_id=str(cfg["store_id"]),
store_root=Path(str(cfg["store_root"])),
allowed_operations=frozenset(map(str,cfg["allowed_operations"])),
expected_owner_uid=int(cfg.get("expected_owner_uid", defaults.get("expected_owner_uid",0))),
allowed_directory_modes=frozenset(mode(x) for x in cfg.get("allowed_directory_modes",defaults.get("allowed_directory_modes",["0700","0750"]))),
allowed_receipt_modes=frozenset(mode(x) for x in cfg.get("allowed_receipt_modes",defaults.get("allowed_receipt_modes",["0600","0640"]))),
authentication_kind=str(cfg.get("authentication_kind",defaults.get("authentication_kind","root-owned-store-v1"))),
max_age_seconds=cfg.get("max_age_seconds",defaults.get("max_age_seconds")),
)
return TrustedProviderReceiptResolver(policies), policies
def git(repo, *args):
p = subprocess.run(["git",*args],cwd=str(repo),text=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE,check=False)
if p.returncode:
raise SystemExit(f"GIT_PRECHECK_FAILED {' '.join(args)}: {p.stderr.strip()}")
return p.stdout.strip()
def main():
ap=argparse.ArgumentParser()
ap.add_argument("--source-oid",required=True)
ap.add_argument("--tree-oid",required=True)
ap.add_argument("--checkout",required=True)
ap.add_argument("--policy",required=True)
ap.add_argument("--run-id",default=None)
args=ap.parse_args()
source=_validate_oid(args.source_oid,"source_oid")
tree=_validate_oid(args.tree_oid,"tree_oid")
repo=Path(args.checkout).resolve()
if git(repo,"rev-parse","HEAD^{commit}").lower()!=source:
raise SystemExit("FINAL_SOURCE_HEAD_MISMATCH")
if git(repo,"rev-parse",f"{source}^{{tree}}").lower()!=tree:
raise SystemExit("FINAL_SOURCE_TREE_MISMATCH")
if git(repo,"status","--porcelain"):
raise SystemExit("FINAL_SOURCE_WORKTREE_DIRTY")
run_id=args.run_id or datetime.now(timezone.utc).strftime("%Y%m%dT%H%M%SZ")
resolver,policies=build_resolver(args.policy)
os.environ["AIOS_REPO_ROOT"]=str(repo)
os.environ.setdefault("AIOS_GITLEAKS_BIN","/usr/bin/gitleaks")
produced=[]
mechanism_required=[]
for kind in GATE_W:
ref=f"round3-gate-w/{source[:12]}/{run_id}/{kind}.json"
try:
if kind=="gitea":
sha,_payload=produce_gitea_consistency_receipt(
repo_root=repo,
source_oid=source,
tree_oid=tree,
policy_path=args.policy,
receipt_ref=ref,
)
else:
sha=produce(
kind,
source_oid=source,
tree_oid=tree,
receipt_ref=ref,
store_root=policies[kind].store_root,
)
produced.append((kind,ref,sha))
except TrustedProviderExecutionError as exc:
if "PROVIDER_MECHANISM_REQUIRED" in str(exc):
mechanism_required.append((kind,str(exc)))
else:
raise
auth_ok=True
results={}
for kind,ref,sha in produced:
r=resolver.resolve(kind,ref,source_oid=source,tree_oid=tree)
results[kind]=dict(r.result)
print(f"[AUTH PASS] {kind} ref={ref} sha={sha} result={json.dumps(r.result,sort_keys=True)}")
expected=set(GATE_W)
closed={k for k,_,_ in produced}
auth_closed=auth_ok and closed==expected and not mechanism_required
test_gate=bool(results.get("tests",{}).get("passed") is True)
secret_gate=bool(results.get("secret_scan",{}).get("passed") is True)
gitea_gate=bool(results.get("gitea",{}).get("consistent") is True)
gate_ready=auth_closed and test_gate and secret_gate and gitea_gate
summary={
"source_oid":source,
"tree_oid":tree,
"run_id":run_id,
"authenticated_providers":sorted(closed),
"mechanism_required":[k for k,_ in mechanism_required],
"provider_auth_closed":auth_closed,
"tests_result_passed":test_gate,
"secret_scan_result_passed":secret_gate,
"gitea_consistent":gitea_gate,
"gate_w_ready":gate_ready,
}
print("GATE_W_PROVE="+json.dumps(summary,sort_keys=True))
if mechanism_required:
return 2
if not auth_closed:
return 1
if not gate_ready:
return 3
return 0
if __name__=="__main__":
raise SystemExit(main())