railiance-platform/scripts/provision-reuse-surface-forgejo-source.py
codex a570bc2f5b Prepare restricted seven-source reuse reader and bounded recovery
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a137ca-5c77-7a71-b9ae-23ad9b0b5684
2026-10-15 01:25:46 +02:00

383 lines
21 KiB
Python
Executable file

#!/usr/bin/env python3
"""Silent attended CCR-2026-0046 bootstrap; never runs without exact approval.
Only this seven-repository identity/PAT/KV path is mutable. No policy, ESO,
consumer rollout, or registration mutations occur here. A receipt is evidence,
not authorization. Uncertain requests are recorded and reconciled, never retried
in the same execution; orphan PAT drift requires attended recovery.
"""
from __future__ import annotations
import argparse
import base64
import datetime as dt
import fcntl
import hashlib
import json
import os
from pathlib import Path
import re
import secrets
import subprocess
import sys
import urllib.error
import urllib.request
import yaml
ROOT = Path(__file__).resolve().parent.parent
CCR = 'CCR-2026-0046'
CCR_FILE = 'credential-change-requests/CCR-2026-0046-reuse-surface-forgejo-source-read.yaml'
PLAN_FILE = 'docs/proposals/2026-10-15-reuse-private-reader/bootstrap-contract.json'
SCRIPT_FILE = 'scripts/provision-reuse-surface-forgejo-source.py'
API = 'https://forgejo.coulomb.social/api/v1'
USER = 'reuse-surface-source'
TEAM = 'reuse-surface-source-readers'
ORG = 'coulomb'
KV = 'platform/workloads/reuse/reuse-surface/forgejo-source-read'
FIELD = 'FORGEJO_SOURCE_TOKEN'
PREFIX = 'reuse-surface-source-read-'
REPOS = frozenset('rapp-openbao rapp-policy-nexus rapp-postgres rapp-sbom-nexus rapp-telemetry rapp-tenant-engine rapp-user-engine'.split())
SCOPES = ['read:repository']
UNITS = {'repo.code': 'read', **{x: 'none' for x in ('repo.actions', 'repo.packages', 'repo.issues', 'repo.ext_issues', 'repo.wiki', 'repo.pulls', 'repo.releases', 'repo.projects', 'repo.ext_wiki')}}
class Refused(Exception):
"""Messages must be fixed non-secret codes, never provider text."""
class NoRedirect(urllib.request.HTTPRedirectHandler):
def redirect_request(self, *args, **kwargs):
raise Refused('redirect_refused')
class Journal:
def __init__(self, path):
flags = os.O_RDWR | os.O_CREAT | os.O_APPEND | os.O_NOFOLLOW
self.fd = os.open(path, flags, 0o600)
if os.fstat(self.fd).st_mode & 0o077:
os.close(self.fd)
raise Refused('receipt_permissions')
fcntl.flock(self.fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
self.attempt = secrets.token_hex(12)
def put(self, event, **fields):
# Only locally authored operation tags, scalar status/IDs are accepted.
allowed = {'operation', 'status', 'http_status', 'token_id', 'team_id', 'outcome', 'error_code'}
if set(fields) - allowed:
raise Refused('receipt_fields')
record = {'at': dt.datetime.now(dt.timezone.utc).isoformat(), 'ccr': CCR,
'attempt': self.attempt, 'event': event, **fields}
data = (json.dumps(record, sort_keys=True) + '\n').encode()
while data:
written = os.write(self.fd, data)
if written <= 0:
raise Refused('receipt_write_failed')
data = data[written:]
os.fsync(self.fd)
def close(self):
os.close(self.fd)
class Client:
def __init__(self, admin, journal):
self.admin, self.journal = admin, journal
self.opener = urllib.request.build_opener(NoRedirect())
def request(self, method, path, payload=None, expected=(200,), *, token=None, sudo=False, basic=None, operation=None):
if not path.startswith('/') or '://' in path:
raise Refused('invalid_api_path')
headers = {'Authorization': basic or 'token ' + (self.admin if token is None else token), 'Accept': 'application/json'}
if sudo:
headers['Sudo'] = USER
if payload is not None:
headers['Content-Type'] = 'application/json'
if method != 'GET':
if not operation:
raise Refused('mutation_without_intent')
self.journal.put('intent', operation=operation)
req = urllib.request.Request(API + path, data=None if payload is None else json.dumps(payload).encode(), headers=headers, method=method)
self.last_total_count = None
try:
with self.opener.open(req, timeout=30) as response:
status, body = response.status, response.read(2_000_001)
raw_total = response.headers.get('X-Total-Count')
if raw_total is not None:
if not re.fullmatch(r'[0-9]+', raw_total):
raise Refused('invalid_total_count')
self.last_total_count = int(raw_total)
except urllib.error.HTTPError as error:
status, body = error.code, b''
except Exception:
if operation:
self.journal.put('outcome', operation=operation, status='ambiguous')
raise Refused('request_observation_failed') from None
if operation:
self.journal.put('outcome', operation=operation, status='observed', http_status=status)
if status not in expected:
raise Refused('unexpected_http_status')
if len(body) > 2_000_000:
raise Refused('response_bound_exceeded')
if not body:
return status, None
try:
return status, json.loads(body)
except Exception:
raise Refused('invalid_json') from None
def pages(self, path, *, sudo=False):
"""Page until observed empty; requested size may be server-clamped.
Forgejo11.0.3 default MaxResponseItems=50, so a response shorter than
our requested100 proves nothing. Detect unstable/duplicate IDs and
reconcile X-Total-Count whenever available; exceeding bound refuses.
"""
items, seen, expected_total = [], set(), None
for page in range(1, 21):
separator = '&' if '?' in path else '?'
_, batch = self.request('GET', path + separator + f'limit=100&page={page}', sudo=sudo)
if not isinstance(batch, list) or any(not isinstance(x, dict) or type(x.get('id')) is not int or x['id'] <= 0 for x in batch):
raise Refused('invalid_list')
observed_total = getattr(self, 'last_total_count', None)
if observed_total is not None:
if expected_total is not None and observed_total != expected_total:
raise Refused('unstable_total_count')
expected_total = observed_total
if not batch:
if expected_total is not None and len(items) != expected_total:
raise Refused('total_count_mismatch')
return items
for item in batch:
if item['id'] in seen:
raise Refused('duplicate_page_id')
seen.add(item['id'])
items.extend(batch)
if expected_total is not None and len(items) > expected_total:
raise Refused('total_count_mismatch')
raise Refused('pagination_bound_exceeded')
class Bao:
@staticmethod
def run(args, stdin=None):
try:
return subprocess.run(['bao', *args], input=stdin, capture_output=True, timeout=60, check=False, cwd=ROOT)
except Exception:
raise Refused('bao_observation_failed') from None
def get(self):
result = self.run(['kv', 'get', '-format=json', KV])
if result.returncode != 0:
# Distinguish an actual not-found response from denied/unavailable.
# Never include captured raw errors in any evidence.
if re.search(rb'Code:\s*404\b', result.stderr or b'') or b'No value found at ' in (result.stderr or b''):
return None
raise Refused('bao_preflight_failed')
try:
data = json.loads(result.stdout)['data']['data']
except Exception:
raise Refused('bao_invalid_record') from None
if set(data) != {FIELD, 'API_USER', 'API_BASE_URL', 'TOKEN_SCOPES', 'GENERATED_AT', 'CCR_ID'} or data['API_USER'] != USER or data['API_BASE_URL'] != 'https://forgejo.coulomb.social' or data['TOKEN_SCOPES'] != 'read:repository' or data['CCR_ID'] != CCR or not isinstance(data[FIELD], str) or not data[FIELD]:
raise Refused('bao_record_conflict')
return data
def put(self, token, journal):
journal.put('intent', operation='kv_create')
timestamp = dt.datetime.now(dt.timezone.utc).isoformat()
try:
result = self.run(['kv', 'put', '-cas=0', KV, FIELD + '=-', 'API_USER=' + USER,
'API_BASE_URL=https://forgejo.coulomb.social', 'TOKEN_SCOPES=read:repository',
'GENERATED_AT=' + timestamp, 'CCR_ID=' + CCR], token.encode())
except Refused:
journal.put('outcome', operation='kv_create', status='ambiguous')
raise
journal.put('outcome', operation='kv_create', status='observed' if result.returncode == 0 else 'ambiguous')
# Readback reconciles even a response failure after successful write.
stored = self.get()
if stored is None or not secrets.compare_digest(stored[FIELD], token):
raise Refused('bao_write_requires_reconciliation')
journal.put('verified', operation='kv_create', status='matched')
def valid_user(user):
return isinstance(user, dict) and user.get('login') == USER and user.get('restricted') is True and user.get('is_admin') is False and user.get('visibility') == 'private'
def valid_team(team):
return isinstance(team, dict) and isinstance(team.get('id'), int) and team.get('name') == TEAM and team.get('permission') == 'read' and team.get('includes_all_repositories') is False and team.get('can_create_org_repo') is False and team.get('units_map') == UNITS
def repo_names(items):
names = set()
for repo in items:
if repo.get('owner', {}).get('login') != ORG or repo.get('name') not in REPOS:
raise Refused('unexpected_team_repository')
names.add(repo['name'])
if len(names) != len(items):
raise Refused('duplicate_repository')
return names
def inspect(client, bao):
"""Read-only preflight before mutations.
Forgejo11.0.3 ListMyRepos uses OwnerID plus Collaborate=None; model
ValueOrDefault(true) includes direct access and team grants (not only owned).
Deployed-server API compatibility and live scope proof remain separate gates.
"""
for repo in sorted(REPOS):
_, meta = client.request('GET', f'/repos/{ORG}/{repo}')
if not isinstance(meta, dict) or meta.get('private') is not True or meta.get('full_name') != ORG + '/' + repo:
raise Refused('source_repository_conflict')
_, probe = client.request('GET', '/repos/coulomb/rapp-core-hub')
if not isinstance(probe, dict) or probe.get('private') is not True:
raise Refused('negative_probe_not_private')
_, user = client.request('GET', '/users/' + USER, expected=(200, 404))
if user is not None and not valid_user(user):
raise Refused('user_conflict')
teams = [x for x in client.pages(f'/orgs/{ORG}/teams') if x.get('name') == TEAM]
if len(teams) > 1:
raise Refused('duplicate_team')
team = teams[0] if teams else None
members, repos = [], set()
if team is not None:
if not valid_team(team):
raise Refused('team_conflict')
members = client.pages('/teams/' + str(team['id']) + '/members')
if len(members) > 1 or any(x.get('login') != USER for x in members):
raise Refused('team_members_conflict')
repos = repo_names(client.pages('/teams/' + str(team['id']) + '/repos'))
tokens = []
if user is not None:
orgs = client.pages('/user/orgs', sudo=True)
if any(x.get('username') != ORG for x in orgs):
raise Refused('extra_organization_affiliation')
grants = client.pages('/user/teams', sudo=True)
if any(x.get('name') != TEAM or x.get('organization', {}).get('username') != ORG for x in grants):
raise Refused('extra_team_grant')
for meta in client.pages('/user/repos?order_by=id', sudo=True):
if meta.get('private') is True and meta.get('full_name') not in {ORG + '/' + x for x in REPOS}:
raise Refused('extra_private_repository_grant')
if meta.get('owner', {}).get('login') == USER:
raise Refused('service_user_owned_repository')
tokens = client.pages('/users/' + USER + '/tokens')
if len(tokens) > 1 or any(not str(x.get('name', '')).startswith(PREFIX) or x.get('scopes') != SCOPES or not isinstance(x.get('id'), int) for x in tokens):
raise Refused('token_conflict')
stored = bao.get()
if bool(tokens) != bool(stored):
raise Refused('orphan_token_or_kv_requires_recovery')
if tokens and (not isinstance(tokens[0].get('token_last_eight'), str) or len(tokens[0]['token_last_eight']) != 8 or not secrets.compare_digest(tokens[0]['token_last_eight'], stored[FIELD][-8:])):
raise Refused('pat_kv_binding_unverifiable')
if tokens and (not team or repos != REPOS or len(members) != 1):
raise Refused('active_lane_grant_drift')
return user, team, repos, members, tokens, stored
def verify(client, source_token, plan):
for source in plan['sources']:
_, repo = client.request('GET', '/repos/' + ORG + '/' + source['repo'], token=source_token)
if repo.get('permissions') != {'admin': False, 'push': False, 'pull': True}:
raise Refused('effective_permission_not_read')
# Exact consented bytes fetched quietly; raw output is never retained.
path = f"/repos/{ORG}/{source['repo']}/contents/registry/indexes/capabilities.yaml?ref={source['consented_commit']}"
_, content = client.request('GET', path, token=source_token)
try:
raw = base64.b64decode(content['content'], validate=False)
except Exception:
raise Refused('invalid_index_encoding') from None
if hashlib.sha256(raw).hexdigest() != source['index_sha256']:
raise Refused('index_digest_mismatch')
client.request('GET', f"/repos/{ORG}/{source['repo']}/actions/secrets?limit=1", token=source_token, expected=(403, 404))
client.request('GET', '/admin/users', token=source_token, expected=(403, 404))
# A known private excluded source is selected by reviewed contract.
probe = plan['negative_private_probe']
_, meta = client.request('GET', '/repos/' + ORG + '/' + probe)
if not isinstance(meta, dict) or meta.get('private') is not True:
raise Refused('negative_probe_not_private')
client.request('GET', '/repos/' + ORG + '/' + probe, token=source_token, expected=(403, 404))
client.journal.put('verified', operation='reader_scope', status='seven_exact_no_extra_private_grants')
def provision(client, bao, plan):
user, team, repos, members, tokens, stored = inspect(client, bao)
if tokens:
verify(client, stored[FIELD], plan)
client.journal.put('terminal', outcome='verified_noop')
return 'noop'
if user is None:
_, user = client.request('POST', '/admin/users', {'username': USER, 'email': USER + '@coulomb.social', 'full_name': 'Reuse Surface seven-source reader', 'password': secrets.token_urlsafe(48), 'restricted': True, 'must_change_password': False, 'send_notify': False, 'visibility': 'private'}, expected=(201,), operation='user_create')
if not valid_user(user):
raise Refused('created_user_contract_failed')
if team is None:
_, team = client.request('POST', f'/orgs/{ORG}/teams', {'name': TEAM, 'description': CCR + ' exact seven consented source repos', 'permission': 'read', 'includes_all_repositories': False, 'can_create_org_repo': False, 'units': ['repo.code'], 'units_map': UNITS}, expected=(201,), operation='team_create')
if not valid_team(team):
raise Refused('created_team_contract_failed')
team_id = team['id']
for repo in sorted(REPOS - repos):
client.request('PUT', f'/teams/{team_id}/repos/{ORG}/{repo}', expected=(204,), operation='team_repo_' + repo)
if not members:
client.request('PUT', f'/teams/{team_id}/members/{USER}', expected=(204,), operation='team_member_add')
# Recheck complete grants before creating any PAT; refuse implicit grants.
_, _, actual_repos, actual_members, _, _ = inspect(client, bao)
if actual_repos != REPOS or len(actual_members) != 1:
raise Refused('incomplete_team_scope')
password = secrets.token_urlsafe(48)
client.request('PATCH', '/admin/users/' + USER, {'password': password, 'restricted': True, 'admin': False, 'allow_create_organization': False, 'allow_git_hook': False, 'allow_import_local': False, 'max_repo_creation': 0, 'must_change_password': False, 'active': True, 'visibility': 'private'}, operation='service_password_randomize')
basic = 'Basic ' + base64.b64encode((USER + ':' + password).encode()).decode()
_, record = client.request('POST', '/users/' + USER + '/tokens', {'name': PREFIX + client.journal.attempt, 'scopes': SCOPES}, expected=(201,), basic=basic, operation='pat_create')
if not isinstance(record, dict) or not isinstance(record.get('id'), int) or record.get('scopes') != SCOPES or not isinstance(record.get('sha1'), str) or not record['sha1']:
raise Refused('created_pat_requires_recovery')
client.journal.put('identified', operation='pat_create', token_id=record['id'], team_id=team_id)
token = record['sha1']
verify(client, token, plan)
bao.put(token, client.journal)
# Repeat complete grant inventory after custody; verify exactly one PAT.
inspect(client, bao)
client.journal.put('terminal', outcome='provisioned_verified_delivery_pending')
return 'minted'
def approval(path):
try:
receipt = json.loads(Path(path).read_text())
ccr = yaml.safe_load((ROOT / CCR_FILE).read_text())
if receipt['ccr_id'] != CCR or receipt['decision'] != 'approved' or not receipt['supervisor'] or not receipt['decision_ref'] or ccr['status'] != 'approved':
raise Refused('approval_missing')
files = {CCR_FILE, PLAN_FILE, SCRIPT_FILE, 'openbao/policies/workload-kv-read-reuse-surface-runtime-eso.hcl'}
if set(receipt['approved_artifacts']) != files:
raise Refused('approval_artifact_set')
for rel in files:
if hashlib.sha256((ROOT / rel).read_bytes()).hexdigest() != receipt['approved_artifacts'][rel]:
raise Refused('approval_revision_mismatch')
plan = json.loads((ROOT / PLAN_FILE).read_text())
if {x['repo'] for x in plan['sources']} != REPOS or len(plan['sources']) != 7 or plan['negative_private_probe'] != 'rapp-core-hub' or any(not re.fullmatch(r'[a-f0-9]{40}', x['consented_commit']) or not re.fullmatch(r'[a-f0-9]{64}', x['index_sha256']) for x in plan['sources']):
raise Refused('plan_scope_conflict')
return plan
except Refused:
raise
except Exception:
raise Refused('approval_invalid') from None
def main(argv=None):
parser = argparse.ArgumentParser()
parser.add_argument('--approval', required=True)
parser.add_argument('--receipt', required=True)
parser.add_argument('--inner', action='store_true', help=argparse.SUPPRESS)
args = parser.parse_args(argv)
journal = None
lane_lock = None
try:
plan = approval(args.approval)
if not args.inner:
# Governed OpenBao attended lane surrounds this command. Warden
# supplies only Forgejo API_TOKEN to inner child, not via argv/files.
result = subprocess.run(['warden', 'access', 'forgejo-admin-api-token', '--field', 'API_TOKEN', '--exec', '--', sys.executable, str(ROOT / SCRIPT_FILE), '--inner', '--approval', str(Path(args.approval).resolve()), '--receipt', str(Path(args.receipt).resolve())], capture_output=True, timeout=900, check=False, cwd=ROOT)
return 0 if result.returncode == 0 else 1
lane_lock = os.open('/tmp/' + CCR + '-reuse-reader-' + str(os.getuid()) + '.lock', os.O_RDWR | os.O_CREAT | os.O_NOFOLLOW, 0o600)
if os.fstat(lane_lock).st_uid != os.getuid() or os.fstat(lane_lock).st_mode & 0o077:
raise Refused('lane_lock_owner_or_permissions')
fcntl.flock(lane_lock, fcntl.LOCK_EX | fcntl.LOCK_NB)
journal = Journal(args.receipt)
admin = os.environ.get('API_TOKEN')
if not admin:
raise Refused('admin_route_missing')
provision(Client(admin, journal), Bao(), plan)
return 0
except Exception as error:
if journal:
journal.put('terminal', outcome='stopped_reconcile_before_retry', error_code=str(error) if isinstance(error, Refused) else 'internal_failure')
return 1
finally:
if journal:
journal.close()
if lane_lock is not None:
os.close(lane_lock)
if __name__ == '__main__':
try:
result = main()
except Exception:
result = 1
raise SystemExit(result)