"""Silent create-only token-exchange proof; no sitting POST.""" import base64 import json import os import stat from pathlib import Path from urllib.error import HTTPError from urllib.parse import urlencode from urllib.request import ProxyHandler, Request, build_opener, HTTPRedirectHandler import jwt ROOT = Path('/home/worsch/railiance-platform') RECEIPT = ROOT / 'docs/evidence/2026-09-15-sitting-requester-exchange.json' POLICY = 'workload-kv-read-informed-decision-sitting-requester-client' KV = 'platform/data/workloads/informed-decision/sitting-requester' SIBLING = 'platform/data/workloads/secrets-engine/approval-requester' PARENT = 'platform/metadata/workloads/informed-decision' ISSUER = 'https://kc.coulomb.social' CLIENT_ID = 'informed-decision-sitting-requester' class NoRedirect(HTTPRedirectHandler): def redirect_request(self, *args, **kwargs): return None def http(url, *, body=None, headers=None): req = Request(url, data=body, headers=headers or {}) try: with build_opener(ProxyHandler({}), NoRedirect()).open(req, timeout=20) as response: content = response.read(1048577) status = response.status except HTTPError as error: status = error.code content = error.read(1048577) error.close() if len(content) > 1048576: raise ValueError('response_too_large') return status, json.loads(content) if content else {} def bao(*args): import subprocess p = subprocess.run(['bao', *args], capture_output=True, text=True, timeout=20) if p.returncode: raise ValueError('metadata_failed') return json.loads(p.stdout) def check_identity(data): policies = set(data.get('policies', [])) | set(data.get('identity_policies', [])) if POLICY not in policies or policies - {POLICY, 'default'} or not data.get('entity_id') or not 0 < data.get('ttl', 0) <= 900: raise ValueError('reader_identity_failed') def main(receipt): if Path.home().parent.name != '.warden-attended-login' or os.getenv('BAO_TOKEN') or os.getenv('VAULT_TOKEN'): raise ValueError('attended_reader_required') check_identity(bao('token', 'lookup', '-format=json')['data']) for path, expected in ((KV, ['read']), (SIBLING, ['deny']), (PARENT, ['deny'])): result = bao('token', 'capabilities', '-format=json', path) if isinstance(result, dict): result = result.get('data', result).get('capabilities', result) if result != expected: raise ValueError('reader_scope_failed') helper = Path.home() / '.vault-token' info = helper.lstat() if not stat.S_ISREG(info.st_mode) or stat.S_IMODE(info.st_mode) != 0o600 or info.st_uid != os.getuid(): raise ValueError('private_helper_required') addr = os.environ.get('BAO_ADDR', 'http://127.0.0.1:18200').rstrip('/') status, data = http(addr + '/v1/' + KV + '?version=1', headers={'X-Vault-Token': helper.read_text().strip()}) if status != 200 or data['data']['metadata']['version'] != 1: raise ValueError('requester_delivery_failed') secret = data['data']['data']['CLIENT_SECRET'] del data def exchange(scope, credential=secret): auth = base64.b64encode((CLIENT_ID + ':' + credential).encode()).decode() return http(ISSUER + '/token', body=urlencode({'grant_type': 'client_credentials', 'scope': scope}).encode(), headers={'Authorization': 'Basic ' + auth, 'Content-Type': 'application/x-www-form-urlencoded'}) status, tokens = exchange('approval:create') if status != 200: raise ValueError('requester_exchange_failed') token = tokens['access_token'] status, jwks = http(ISSUER + '/jwks') if status != 200: raise ValueError('jwks_failed') header = jwt.get_unverified_header(token) keys = [key for key in jwks['keys'] if key['kid'] == header.get('kid')] if header.get('alg') != 'RS256' or len(keys) != 1: raise ValueError('signing_key_failed') claims = jwt.decode(token, jwt.PyJWK.from_dict(keys[0]).key, algorithms=['RS256'], issuer=ISSUER, audience='approval-engine', options={'strict_aud': True, 'require': ['sub', 'iat', 'exp', 'iss', 'aud']}) expected = {'sub': 'informed-decision', 'tenant': 'tenant:platform', 'principal_type': 'service', 'scope': 'approval:create', 'roles': ['informed-decision-sitting-requester'], 'groups': []} if any(claims.get(key) != value for key, value in expected.items()) or claims['exp'] - claims['iat'] != 900: raise ValueError('requester_claims_failed') for scope in ('approval:approve', 'approval:consume', 'approval:read'): if exchange(scope)[0] != 400: raise ValueError('excess_scope_not_refused') if exchange('approval:create', 'invalid-synthetic-credential')[0] != 401: raise ValueError('wrong_secret_not_refused') receipt.update(status='verified', phase='requester_verified', signature_verified=True, excess_scopes_refused=True, wrong_secret_refused=True, reader_scope_verified=True, sitting_post=False) if __name__ == '__main__': if RECEIPT.exists(): raise SystemExit(1) receipt = {'observed_at': __import__('datetime').datetime.now(__import__('datetime').timezone.utc).isoformat(), 'status': 'failed', 'phase': 'preflight', 'credential_values_emitted': False, 'sitting_post': False} try: main(receipt) except Exception: raise SystemExit(1) from None finally: RECEIPT.write_text(json.dumps(receipt, indent=2) + '\n')