#!/usr/bin/env python3 """Attended first bootstrap for CCR-2026-0014 (silent on success).""" from __future__ import annotations import argparse import datetime as dt import json import os from pathlib import Path import secrets import subprocess import sys import urllib.error import urllib.parse import urllib.request API_ROOT = "https://forgejo.coulomb.social/api/v1" BAO_PATH = "platform/workloads/policy-nexus/forgejo-source-read" ORG = "coulomb" REPO = "policy-nexus" USER = "policy-nexus-source" TEAM = "policy-nexus-source-readers" SECRET = "FORGEJO_SOURCE_TOKEN" TOKEN_PREFIX = "policy-nexus-source-read-" SCOPES = ["read:repository"] REPO_DIR = Path(__file__).resolve().parent.parent DIAGNOSTIC_PATH = Path("/tmp/policy-nexus-source-bootstrap-diagnostic.json") NON_CODE_UNITS = ( "repo.actions", "repo.packages", "repo.issues", "repo.ext_issues", "repo.wiki", "repo.pulls", "repo.releases", "repo.projects", "repo.ext_wiki", ) class ProvisionError(RuntimeError): pass def write_diagnostic(stage: str, error: Exception | None = None) -> None: detail = str(error) if isinstance(error, ProvisionError) else "unexpected internal error" DIAGNOSTIC_PATH.write_text( json.dumps({"stage": stage, "detail": detail}, sort_keys=True) + "\n" ) DIAGNOSTIC_PATH.chmod(0o600) def api_request( token: str, method: str, path: str, *, payload: dict[str, object] | None = None, expected: tuple[int, ...] = (200,), read_body: bool = True, ) -> tuple[int, object | None]: data = None if payload is None else json.dumps(payload).encode() request = urllib.request.Request( API_ROOT + path, data=data, method=method, headers={ "Authorization": f"token {token}", "Accept": "application/json", **({"Content-Type": "application/json"} if data is not None else {}), }, ) try: with urllib.request.urlopen(request, timeout=30) as response: status = response.status body = response.read() if read_body else response.read(1) except urllib.error.HTTPError as error: status = error.code body = b"" if status not in expected: raise ProvisionError(f"{method} {path} returned HTTP {status}") if not read_body or not body: return status, None try: return status, json.loads(body) except json.JSONDecodeError as error: raise ProvisionError(f"{method} {path} returned invalid JSON") from error def bao(args: list[str], *, stdin: bytes | None = None) -> subprocess.CompletedProcess[bytes]: return subprocess.run( ["bao", *args], cwd=REPO_DIR, input=stdin, capture_output=True, check=False, timeout=60, ) def require_empty_destinations(admin_token: str, existing_tokens: list[dict[str, object]]) -> None: if any(str(item.get("name", "")).startswith(TOKEN_PREFIX) for item in existing_tokens): raise ProvisionError("a Policy Nexus source PAT already exists; use the rotation procedure") _, action_secrets = api_request( admin_token, "GET", f"/repos/{ORG}/{REPO}/actions/secrets?limit=100", ) if not isinstance(action_secrets, list): raise ProvisionError("Forgejo returned an invalid Actions-secret list") if any(item.get("name") == SECRET for item in action_secrets): raise ProvisionError("FORGEJO_SOURCE_TOKEN already exists; use the rotation procedure") if bao(["kv", "get", "-field=FORGEJO_SOURCE_TOKEN", BAO_PATH]).returncode == 0: raise ProvisionError("the OpenBao destination already contains a source token") def ensure_user(admin_token: str) -> None: status, user = api_request(admin_token, "GET", f"/users/{USER}", expected=(200, 404)) if status == 404: _, user = api_request( admin_token, "POST", "/admin/users", payload={ "username": USER, "email": "policy-nexus-source@coulomb.social", "full_name": "Policy Nexus source reader", "password": secrets.token_urlsafe(48), "restricted": True, "must_change_password": False, "send_notify": False, "visibility": "private", }, expected=(201,), ) if not isinstance(user, dict): raise ProvisionError("Forgejo returned an invalid service user") if user.get("login") != USER or user.get("restricted") is not True or user.get("is_admin") is True: raise ProvisionError("service user does not satisfy the restricted non-admin contract") def ensure_team(admin_token: str) -> int: _, teams = api_request(admin_token, "GET", f"/orgs/{ORG}/teams?limit=100") if not isinstance(teams, list): raise ProvisionError("Forgejo returned an invalid team list") team = next((item for item in teams if item.get("name") == TEAM), None) if team is None: units_map = {unit: "none" for unit in NON_CODE_UNITS} units_map["repo.code"] = "read" _, team = api_request( admin_token, "POST", f"/orgs/{ORG}/teams", payload={ "name": TEAM, "description": "Read-only source acquisition for Policy Nexus publication", "permission": "read", "includes_all_repositories": True, "can_create_org_repo": False, "units": ["repo.code"], "units_map": units_map, }, expected=(201,), ) if not isinstance(team, dict) or not isinstance(team.get("id"), int): raise ProvisionError("Forgejo returned an invalid source-reader team") units_map = team.get("units_map") or {} if ( team.get("permission") != "read" or team.get("includes_all_repositories") is not True or team.get("can_create_org_repo") is not False or units_map.get("repo.code") != "read" or any(units_map.get(unit, "none") != "none" for unit in NON_CODE_UNITS) ): raise ProvisionError("source-reader team does not satisfy the least-privilege contract") team_id = int(team["id"]) api_request( admin_token, "PUT", f"/teams/{team_id}/members/{USER}", expected=(204,), ) return team_id def verify_source_token(source_token: str, scopes: object) -> None: if scopes != SCOPES: raise ProvisionError("Forgejo returned scopes broader than read:repository") _, branch = api_request(source_token, "GET", f"/repos/{ORG}/{REPO}/branches/main") if not isinstance(branch, dict) or not isinstance(branch.get("commit"), dict): raise ProvisionError("source token could not resolve the main branch") revision = branch["commit"].get("id") if not isinstance(revision, str) or len(revision) != 40: raise ProvisionError("source token returned an invalid main revision") api_request( source_token, "GET", f"/repos/{ORG}/{REPO}/archive/{urllib.parse.quote(revision)}.tar.gz", expected=(200,), read_body=False, ) api_request(source_token, "GET", "/admin/users", expected=(403, 404)) api_request( source_token, "GET", f"/repos/{ORG}/{REPO}/actions/secrets?limit=1", expected=(403, 404), ) def verify_effective_permission(admin_token: str) -> None: _, permission = api_request( admin_token, "GET", f"/repos/{ORG}/{REPO}/collaborators/{USER}/permission", ) if not isinstance(permission, dict) or permission.get("permission") != "read": raise ProvisionError("service user effective repository permission is not read-only") def record_evidence(run_id: int | None, token_name: str) -> None: detail = ( f"Restricted user {USER} and all-repository repo.code-read team {TEAM} verified; " f"PAT {token_name} reports exactly read:repository; archive read passed; effective repository " f"permission is read-only; Actions-secret read and instance-admin probes were denied; OpenBao and repository " f"Actions secret were populated without value output; workflow dispatch run_id={run_id}." ) result = subprocess.run( [ sys.executable, "scripts/credential-change.py", "record-evidence", "CCR-2026-0014", "--actor", "attended operator via governed platform-admin lane", "--kind", "forgejo_source_bootstrap", "--result", "passed", "--detail", detail, "--status", "applied", "--record-state-hub", ], cwd=REPO_DIR, capture_output=True, check=False, timeout=120, ) if result.returncode != 0: raise ProvisionError("credential evidence recording failed") def provision(admin_token: str) -> None: ensure_user(admin_token) ensure_team(admin_token) verify_effective_permission(admin_token) _, existing_tokens = api_request(admin_token, "GET", f"/users/{USER}/tokens?limit=100") if not isinstance(existing_tokens, list): raise ProvisionError("Forgejo returned an invalid token list") require_empty_destinations(admin_token, existing_tokens) timestamp = dt.datetime.now(dt.timezone.utc).strftime("%Y%m%dT%H%M%SZ") token_name = TOKEN_PREFIX + timestamp token_id: int | None = None source_token = "" bao_written = False activated = False try: _, created = api_request( admin_token, "POST", f"/users/{USER}/tokens", payload={"name": token_name, "scopes": SCOPES}, expected=(201,), ) if not isinstance(created, dict) or not isinstance(created.get("id"), int): raise ProvisionError("Forgejo returned an invalid access-token record") token_id = int(created["id"]) source_token = str(created.get("sha1") or "") if not source_token: raise ProvisionError("Forgejo did not return the new access token") verify_source_token(source_token, created.get("scopes")) stored = bao( [ "kv", "put", BAO_PATH, "FORGEJO_SOURCE_TOKEN=-", f"API_USER={USER}", "API_BASE_URL=https://forgejo.coulomb.social", "TOKEN_SCOPES=read:repository", f"GENERATED_AT={timestamp}", ], stdin=source_token.encode(), ) if stored.returncode != 0: raise ProvisionError("OpenBao source-token write failed") bao_written = True readback = bao(["kv", "get", "-field=FORGEJO_SOURCE_TOKEN", BAO_PATH]) if readback.returncode != 0 or readback.stdout.strip() != source_token.encode(): raise ProvisionError("OpenBao source-token readback mismatch") api_request( admin_token, "PUT", f"/repos/{ORG}/{REPO}/actions/secrets/{SECRET}", payload={"data": source_token}, expected=(201, 204), ) activated = True _, dispatch = api_request( admin_token, "POST", f"/repos/{ORG}/{REPO}/actions/workflows/publish-image.yaml/dispatches", payload={"ref": "main", "return_run_info": True}, expected=(201, 204), ) run_id = dispatch.get("id") if isinstance(dispatch, dict) else None record_evidence(run_id if isinstance(run_id, int) else None, token_name) except Exception: if not activated and token_id is not None: try: api_request( admin_token, "DELETE", f"/users/{USER}/tokens/{token_id}", expected=(204, 404), ) except Exception: pass if bao_written and not activated: bao(["kv", "delete", BAO_PATH]) raise finally: source_token = "" def outer() -> int: DIAGNOSTIC_PATH.unlink(missing_ok=True) result = subprocess.run( [ "warden", "access", "forgejo-admin-api-token", "--field", "API_TOKEN", "--exec", "--", sys.executable, str(Path(__file__).resolve()), "--inner", ], cwd=REPO_DIR, capture_output=True, check=False, timeout=900, ) if result.returncode != 0 and not DIAGNOSTIC_PATH.exists(): write_diagnostic("forgejo-admin-route") return result.returncode def main() -> int: parser = argparse.ArgumentParser() parser.add_argument("--inner", action="store_true", help=argparse.SUPPRESS) args = parser.parse_args() if not args.inner: return outer() admin_token = os.environ.get("API_TOKEN", "") if not admin_token: raise ProvisionError("Warden did not provide API_TOKEN") try: provision(admin_token) except Exception as error: write_diagnostic("provision", error) raise DIAGNOSTIC_PATH.unlink(missing_ok=True) return 0 if __name__ == "__main__": try: raise SystemExit(main()) except Exception: # The surrounding Warden lane records only the failure and never receives # provider response bodies or credential material. raise SystemExit(1) from None