net-kingdom/sso-mfa/k8s/keycape/openbao-negative-session.py
tegwick dfc357eb8a
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Publish reviewed KEY39 lifecycle source and preserve failed review history
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
2026-10-11 15:33:14 +02:00

712 lines
33 KiB
Python

#!/usr/bin/env python3
"""Founder-attended KEY39 lifecycle. Silent; private values never leave memory/K8s.
inspect is metadata-only (no Secret read). execute requires an exact approved
envelope, source/runtime pins and founder-held private tokens on stdin. No login,
custody fetch, production credential, role or policy mutation is implemented.
"""
import argparse
import base64
import copy
import hashlib
import importlib.util
import json
import math
import os
from pathlib import Path
import secrets
import signal
import subprocess
import threading
import time
from contextlib import contextmanager
import urllib.parse
import urllib.request
import urllib.error
import yaml
CLUSTER = 'a553c742-0115-43d4-99a4-a5ca56fe0786'
TARGET = 'sso/keycape'
PROPOSAL = 'KEY-WP-0039-T02/attended-lifecycle-v5'
IDS = ['openbao-probe-' + c for c in ['aud', 'sub', 'tenant', 'roles', 'scope', 'expiry']]
ENVS = ['KEYCAPE_' + c.upper().replace('-', '_') + '_CLIENT_SECRET' for c in IDS]
TEMP = 'keycape-openbao-negative-key39'
BAO_ORIGINS = {'http://127.0.0.1:18200', 'http://openbao.openbao.svc:8200'}
REQUEST_DEADLINE = None
BUSINESS_MONOTONIC_DEADLINE = None
CLEANUP_MONOTONIC_DEADLINE = None
CLEANING = False
MAX_RESPONSE = 256 * 1024
HTTP_TOTAL_SECONDS = 15
CLEANUP_TOTAL_SECONDS = 300
HTTP_ABORT_SECONDS = 0.02
class Refused(Exception):
pass
def require(ok, reason):
if not ok:
raise Refused(reason)
def digest(data):
return hashlib.sha256(data).hexdigest()
def canonical(value):
return digest(json.dumps(value, sort_keys=True, separators=(',', ':')).encode())
def finite_number(value):
try:
return type(value) in (int, float) and math.isfinite(value)
except OverflowError:
return False
def read_json(raw):
def reject_constant(_):
raise Refused('nonfinite_json_constant')
return json.loads(raw, parse_constant=reject_constant)
def begin_cleanup():
global CLEANUP_MONOTONIC_DEADLINE
if CLEANUP_MONOTONIC_DEADLINE is None:
CLEANUP_MONOTONIC_DEADLINE = time.monotonic() + CLEANUP_TOTAL_SECONDS
def check_deadline():
if CLEANING:
require(CLEANUP_MONOTONIC_DEADLINE is not None
and time.monotonic() < CLEANUP_MONOTONIC_DEADLINE, 'cleanup_budget_expired')
return
if REQUEST_DEADLINE is not None and not CLEANING:
require(finite_number(REQUEST_DEADLINE), 'approved_window_invalid')
require(time.time() < REQUEST_DEADLINE, 'approved_window_expired')
if BUSINESS_MONOTONIC_DEADLINE is not None:
require(time.monotonic() < BUSINESS_MONOTONIC_DEADLINE, 'session_business_budget_expired')
def request_budget(cap, cleanup=False):
require(finite_number(cap) and 0 < cap <= 30, 'request_timeout_invalid')
budget = float(cap)
if cleanup or CLEANING:
if CLEANUP_MONOTONIC_DEADLINE is not None:
budget = min(budget, CLEANUP_MONOTONIC_DEADLINE - time.monotonic())
else:
check_deadline()
if REQUEST_DEADLINE is not None:
budget = min(budget, REQUEST_DEADLINE - time.time())
if BUSINESS_MONOTONIC_DEADLINE is not None:
budget = min(budget, BUSINESS_MONOTONIC_DEADLINE - time.monotonic())
require(budget > 0 and math.isfinite(budget), 'request_window_exhausted')
return budget
@contextmanager
def total_timeout(seconds):
"""Linux main-thread hard elapsed bound, including blocking headers/body reads."""
require(finite_number(seconds) and 0 < seconds <= 30, 'request_timeout_invalid')
require(threading.current_thread() is threading.main_thread()
and hasattr(signal, 'setitimer'), 'main_thread_linux_timer_required')
previous_timer = signal.getitimer(signal.ITIMER_REAL)
require(previous_timer == (0.0, 0.0), 'existing_alarm_timer_refused')
previous_handler = signal.getsignal(signal.SIGALRM)
def expired(*_):
raise Refused('request_total_timeout')
started = time.monotonic()
signal.signal(signal.SIGALRM, expired)
signal.setitimer(signal.ITIMER_REAL, seconds)
try:
yield
require(time.monotonic() - started <= seconds, 'request_total_timeout')
finally:
signal.setitimer(signal.ITIMER_REAL, 0)
signal.signal(signal.SIGALRM, previous_handler)
class NoRedirect(urllib.request.HTTPRedirectHandler):
def redirect_request(self, *args, **kwargs):
return None
class SessionTransport:
"""Fixed origins, no ambient proxy, bounded reads, same guards in cleanup."""
def __init__(self, bao_origin, receipt=None):
require(bao_origin in BAO_ORIGINS, 'bao_origin_invalid')
self.bao_origin = bao_origin
self.receipt = receipt if receipt is not None else {}
self.opener = urllib.request.build_opener(urllib.request.ProxyHandler({}), NoRedirect())
def request(self, url, *, data=None, headers=None, method='POST', timeout=15):
allowed = {'https://kc.coulomb.social/token',
'https://kc.coulomb.social/.well-known/openid-configuration',
self.bao_origin + '/v1/auth/keycape-services/login',
self.bao_origin + '/v1/auth/token/revoke-self'}
require(url in allowed, 'http_target_not_reviewed')
require(method == ('GET' if url.endswith('/.well-known/openid-configuration') else 'POST'),
'http_method_not_reviewed')
cleanup = url.endswith('/v1/auth/token/revoke-self')
budget = request_budget(min(timeout, HTTP_TOTAL_SECONDS), cleanup=cleanup)
total_deadline = time.monotonic() + budget
req = urllib.request.Request(url, data=data, headers=headers or {}, method=method)
response, status, raw = None, None, None
try:
with total_timeout(budget):
try:
response = self.opener.open(req, timeout=budget)
except urllib.error.HTTPError as error:
response = error
except (urllib.error.URLError, OSError):
if url == self.bao_origin + '/v1/auth/keycape-services/login':
self.receipt['openbao_login_outcome_unknown'] = True
return None, b''
status = response.getcode()
raw = response.read(MAX_RESPONSE + 1)
require(len(raw) <= MAX_RESPONSE, 'http_response_oversized')
response.close()
response = None
if not cleanup:
check_deadline()
return status, raw
except Refused:
if url == self.bao_origin + '/v1/auth/keycape-services/login' and status in (None, 200):
# A late response cannot pass; preserve acquired-token cleanup when available.
if raw is not None and status == 200:
self.revoke_late_session(raw)
else:
self.receipt['openbao_login_outcome_unknown'] = True
raise
except (urllib.error.URLError, OSError):
if url == self.bao_origin + '/v1/auth/keycape-services/login':
if raw is not None and status == 200:
self.revoke_late_session(raw)
else:
self.receipt['openbao_login_outcome_unknown'] = True
return None, b''
except Exception:
if url == self.bao_origin + '/v1/auth/keycape-services/login':
if raw is not None and status == 200:
self.revoke_late_session(raw)
else:
self.receipt['openbao_login_outcome_unknown'] = True
raise Refused('http_response_failed') from None
finally:
if response is not None:
self.abort_response(response, total_deadline)
def abort_response(self, response, original_deadline):
"""One bounded exceptional close; never retry or reset the cleanup clock."""
self.receipt['http_abort_close_attempted'] = False
self.receipt['http_abort_close_succeeded'] = False
begin_cleanup()
try:
cap = request_budget(HTTP_ABORT_SECONDS, cleanup=True)
remaining = original_deadline - time.monotonic()
if remaining > 0:
cap = min(cap, remaining)
self.receipt['http_abort_close_attempted'] = True
with total_timeout(cap):
response.close()
self.receipt['http_abort_close_succeeded'] = True
except Exception:
self.receipt['http_response_abort_unconfirmed'] = True
raise Refused('http_response_abort_unconfirmed') from None
def revoke_late_session(self, raw):
self.receipt['late_acceptance_revoke_attempted'] = False
self.receipt['late_acceptance_revoke_succeeded'] = False
try:
token = read_json(raw)['auth']['client_token']
require(isinstance(token, str) and token, 'late_session_response_invalid')
except (KeyError, TypeError, ValueError, Refused):
self.receipt['openbao_login_outcome_unknown'] = True
return
begin_cleanup()
self.receipt['late_acceptance_revoke_attempted'] = True
try:
status, _ = self.post(self.bao_origin + '/v1/auth/token/revoke-self',
body={}, headers={'X-Vault-Token': token})
self.receipt['late_acceptance_revoke_succeeded'] = status == 204
except Exception:
self.receipt['late_acceptance_revoke_succeeded'] = False
finally:
del token
def post(self, url, form=None, body=None, headers=None, timeout=15):
headers = dict(headers or {})
if form is not None:
data = urllib.parse.urlencode(form).encode()
headers['Content-Type'] = 'application/x-www-form-urlencoded'
else:
data = json.dumps(body or {}).encode()
headers['Content-Type'] = 'application/json'
return self.request(url, data=data, headers=headers, timeout=timeout)
def discovery(self):
status, raw = self.request('https://kc.coulomb.social/.well-known/openid-configuration', method='GET')
require(status == 200, 'discovery_failed')
return json.loads(raw)
def k(arguments, payload=None):
# Execute on railiance01 in the founder's session, never workstation defaults.
check_deadline()
budget = request_budget(30)
with total_timeout(budget):
result = subprocess.run(['kubectl', '--kubeconfig=/etc/rancher/k3s/k3s.yaml',
'--request-timeout=20s', *arguments],
input=None if payload is None else json.dumps(payload),
text=True, capture_output=True, timeout=budget)
check_deadline()
require(result.returncode == 0, 'kubernetes_operation_failed')
return json.loads(result.stdout) if result.stdout.strip() else None
def get(kind, name):
return k(['-n', 'sso', 'get', kind, name, '-o', 'json'])
def meta(obj):
return {key: obj['metadata'][key] for key in ['uid', 'resourceVersion']}
def patch(kind, obj, path, value, dry=False):
ops = [{'op': 'test', 'path': '/metadata/' + key, 'value': val}
for key, val in meta(obj).items()]
ops.append({'op': 'replace', 'path': path, 'value': value})
args = ['-n', 'sso', 'patch', kind, obj['metadata']['name'], '--type=json',
'--patch-file=/dev/stdin', '-o', 'json']
if dry:
args += ['--dry-run=server']
return k(args, ops)
def registrations():
reference = {'displayName': 'Temporary KEY39 negative probe',
'allowedScopes': ['openbao:login'], 'grantTypes': ['client_credentials'],
'clientType': 'confidential', 'serviceSubject': 'service:secrets-engine',
'tenant': 'tenant:platform', 'roles': ['secrets-engine'], 'tokenLifetime': '1m'}
result = []
for index, client_id in enumerate(IDS):
c = dict(reference, clientId=client_id, secretRef='env:' + ENVS[index])
if index:
c['audience'] = 'secrets-engine-openbao'
if index == 1:
c['serviceSubject'] = 'service:openbao-probe'
if index == 2:
c['tenant'] = 'tenant:openbao-probe'
if index == 3:
c['roles'] = ['openbao-probe']
if index == 4:
c['allowedScopes'] = ['openbao:probe']
result.append(c)
return result
class UniqueLoader(yaml.SafeLoader):
pass
def unique(loader, node):
result = {}
for key_node, value_node in node.value:
key = loader.construct_object(key_node)
require(key not in result, 'duplicate_yaml_key')
result[key] = loader.construct_object(value_node)
return result
UniqueLoader.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, unique)
def candidate_config(raw):
config = yaml.load(raw, Loader=UniqueLoader)
clients = config['clients']
require(isinstance(clients, list) and clients, 'clients_required')
ids = [c['clientId'] for c in clients]
require(len(ids) == len(set(ids)) and not set(ids).intersection(IDS), 'existing_probe_or_duplicate')
require(not {c.get('secretRef') for c in clients}.intersection('env:' + e for e in ENVS),
'probe_secretref_collision')
production = [c for c in clients if c['clientId'] == 'secrets-engine-openbao']
require(len(production) == 1, 'production_client_missing')
expected = registrations()[-1]
for field in ['allowedScopes', 'grantTypes', 'clientType', 'serviceSubject', 'tenant', 'roles']:
require(production[0].get(field) == expected[field], 'production_claim_contract_drift')
require(production[0].get('audience', production[0]['clientId']) == 'secrets-engine-openbao',
'production_audience_drift')
nodes = yaml.compose(raw)
node = next(v for key, v in nodes.value if key.value == 'clients')
require(isinstance(node, yaml.nodes.SequenceNode) and not node.flow_style,
'block_client_sequence_required')
index = node.end_mark.index
start = raw.rfind('\n', 0, index) + 1
if not raw[start:index].strip():
index = start
fragment = yaml.safe_dump(registrations(), sort_keys=False)
fragment = ''.join(' ' * node.start_mark.column + line if line.strip() else line
for line in fragment.splitlines(True))
if index and raw[index - 1] != '\n':
fragment = '\n' + fragment
updated = raw[:index] + fragment + raw[index:]
intended = copy.deepcopy(config)
intended['clients'].extend(registrations())
require(yaml.load(updated, Loader=UniqueLoader) == intended, 'unrelated_config_changed')
return updated
def candidate_spec(spec):
result = copy.deepcopy(spec)
require(result.get('replicas', 1) == 1 and result['strategy']['type'] == 'Recreate',
'single_replica_recreate_required')
container = next(c for c in result['template']['spec']['containers'] if c['name'] == 'keycape')
env = container['env']
require(not {e['name'] for e in env}.intersection(ENVS), 'probe_env_collision')
env.extend({'name': e, 'valueFrom': {'secretKeyRef': {'name': TEMP, 'key': c}}}
for c, e in zip(IDS, ENVS))
return result
def ready(spec, timeout=150):
deadline = time.monotonic() + timeout
while time.monotonic() < deadline:
dep = get('deployment', 'keycape')
require(dep['spec'] == spec, 'deployment_drift_during_readiness')
status = dep.get('status', {})
if (status.get('observedGeneration') == dep['metadata']['generation']
and all(status.get(key) == 1 for key in
['updatedReplicas', 'readyReplicas', 'availableReplicas', 'replicas'])):
return True
time.sleep(3)
raise Refused('readiness_timeout')
def verify_sources(envelope, recovery=False):
require(envelope.get('proposal_id') == PROPOSAL and envelope.get('target') == TARGET,
'proposal_target_mismatch')
require(envelope.get('disposition') == ('recovery-approved' if recovery else 'approved')
and envelope.get('founder_decision_id'),
'founder_exact_go_required')
require(envelope.get('source_hashes') and
str(Path(__file__).resolve()) in envelope['source_hashes'], 'executor_pin_required')
for filename, expected in envelope['source_hashes'].items():
require(digest(Path(filename).read_bytes()) == expected, 'reviewed_source_changed')
required = ['net-kingdom', 'key-cape', 'railiance-platform']
require(all(envelope.get('owner_acknowledgments', {}).get(owner) for owner in required),
'owner_acknowledgments_required')
expiry = envelope['valid_until_epoch']
maximum = envelope['maximum_session_seconds']
require(finite_number(expiry) and type(maximum) is int and
420 <= maximum <= 900 and 0 < expiry - time.time() <= maximum,
'attended_window_invalid')
if recovery:
return None
role = envelope['role_observation']
require(role['mount'] == 'keycape-services' and role['role'] == 'secrets-engine-openbao'
and role['issuer'] == 'https://kc.coulomb.social' and role['algorithm'] == 'RS256'
and role['bindings_exact'] is True and role['policy_exact'] is True,
'role_owner_observation_required')
leeway = role['raw_expiration_leeway']
require(type(leeway) is int and -1 <= leeway <= 150, 'leeway_outside_session_bound')
effective = 0 if leeway == -1 else leeway or 150
require(role['effective_expiration_leeway'] == effective, 'leeway_normalization_mismatch')
observed = role['observed_at_epoch']
require(finite_number(observed) and 0 <= time.time() - observed <= 300,
'role_observation_stale_or_future')
require(envelope['bao_addr'] in BAO_ORIGINS, 'bao_origin_invalid')
return effective
def load_probe(path):
spec = importlib.util.spec_from_file_location('key39_reviewed_probe', path)
result = importlib.util.module_from_spec(spec)
spec.loader.exec_module(result)
return result
def removed_client_denied(status, raw):
try:
body = json.loads(raw)
return status == 401 and body.get('error') == 'invalid_profile_usage' and body.get('feature') == 'client_id'
except (ValueError, AttributeError, TypeError):
return False
def recovered_config(raw):
config = yaml.load(raw, Loader=UniqueLoader)
clients = config['clients']
ids = [c['clientId'] for c in clients]
present = set(ids).intersection(IDS)
require(len(ids) == len(set(ids)) and present in [set(), set(IDS)], 'partial_probe_registry')
if not present:
return raw
require(clients[-6:] == registrations(), 'recovery_registration_drift')
node = next(v for key, v in yaml.compose(raw).value if key.value == 'clients')
first = node.value[-6].start_mark.index
start = raw.rfind('\n', 0, first) + 1
end = node.end_mark.index
line_start = raw.rfind('\n', 0, end) + 1
if not raw[line_start:end].strip():
end = line_start
restored = raw[:start] + raw[end:]
require(candidate_config(restored) == raw, 'recovery_byte_roundtrip_failed')
return restored
def recovered_spec(spec):
restored = copy.deepcopy(spec)
container = next(c for c in restored['template']['spec']['containers'] if c['name'] == 'keycape')
env = container['env']
expected = [{'name': e, 'valueFrom': {'secretKeyRef': {'name': TEMP, 'key': c}}}
for c, e in zip(IDS, ENVS)]
matches = [e for e in env if e['name'] in ENVS]
require(matches in [[], expected], 'partial_or_drifted_probe_env')
container['env'] = [e for e in env if e['name'] not in ENVS]
return restored
def delete_temporary(created):
# The exact raw API delete needs the same aggregate/per-request guards as patches.
k(['delete', '--raw=/api/v1/namespaces/sso/secrets/' + TEMP, '-f', '/dev/stdin'],
{'apiVersion': 'v1', 'kind': 'DeleteOptions', 'preconditions': meta(created)})
require(k(['-n', 'sso', 'get', 'secret', TEMP, '--ignore-not-found', '-o', 'json']) is None,
'temporary_secret_still_present')
def recover(envelope, receipt):
global REQUEST_DEADLINE, BUSINESS_MONOTONIC_DEADLINE, CLEANUP_MONOTONIC_DEADLINE, CLEANING
verify_sources(envelope, recovery=True)
# Separately approved recovery obligations are cleanup, never business writes.
REQUEST_DEADLINE = None
BUSINESS_MONOTONIC_DEADLINE = None
CLEANUP_MONOTONIC_DEADLINE = None
begin_cleanup()
CLEANING = True
transport = SessionTransport(envelope['bao_addr'], receipt=receipt)
require(k(['get', 'namespace', 'kube-system', '-o', 'json'])['metadata']['uid'] == CLUSTER,
'cluster_identity_changed')
config = get('secret', 'keycape-config')
dep = get('deployment', 'keycape')
raw = base64.b64decode(config['data']['config.yaml'], validate=True).decode()
restored = recovered_config(raw)
spec = recovered_spec(dep['spec'])
require(config['metadata']['uid'] == envelope['config_metadata']['uid']
and dep['metadata']['uid'] == envelope['deployment_metadata']['uid']
and digest(restored.encode()) == envelope['registry_sha256']
and canonical(spec) == envelope['deployment_spec_sha256'], 'recovery_baseline_drift')
temp = get('secret', TEMP)
require(set(temp.get('data', {})) == set(IDS)
and temp['metadata']['uid'] == envelope['temporary_secret_uid'], 'recovery_custody_identity_required')
values = {c: base64.b64decode(temp['data'][c], validate=True).decode() for c in IDS}
if raw != restored:
patch('secret', config, '/data/config.yaml', base64.b64encode(restored.encode()).decode())
if dep['spec'] != spec:
patch('deployment', dep, '/spec', spec)
ready(spec)
after = get('secret', 'keycape-config')
require(after['data'] == dict(config['data'], **{'config.yaml': base64.b64encode(restored.encode()).decode()}),
'recovery_readback_failed')
require(envelope['runner_path'] in envelope['source_hashes'], 'runner_pin_required')
probe = load_probe(envelope['runner_path'])
for client, value in values.items():
basic = base64.b64encode((client + ':' + value).encode()).decode()
status, body = transport.post('https://kc.coulomb.social/token',
form={'grant_type': 'client_credentials', 'scope': 'openbao:login'},
headers={'Authorization': 'Basic ' + basic})
require(removed_client_denied(status, body), 'removed_client_denial_unconfirmed')
observed = get('secret', TEMP)
require(observed['data'] == temp['data'] and observed['metadata']['uid'] == temp['metadata']['uid'],
'recovery_temporary_secret_drift')
delete_temporary(observed)
receipt.update(cleanup_verified=True, recovery_only=True)
def execute(envelope, private, receipt, checkpoint=lambda: None):
global REQUEST_DEADLINE, BUSINESS_MONOTONIC_DEADLINE, CLEANUP_MONOTONIC_DEADLINE, CLEANING
leeway = verify_sources(envelope)
REQUEST_DEADLINE = envelope['valid_until_epoch']
BUSINESS_MONOTONIC_DEADLINE = time.monotonic() + min(
REQUEST_DEADLINE - time.time(), envelope['maximum_session_seconds'] - 180)
CLEANUP_MONOTONIC_DEADLINE = None
CLEANING = False
runner_path = envelope['runner_path']
require(runner_path in envelope['source_hashes'], 'runner_pin_required')
probe = load_probe(runner_path)
transport = SessionTransport(envelope['bao_addr'], receipt=receipt)
discovery = transport.discovery()
require(discovery.get('issuer') == 'https://kc.coulomb.social' and
discovery.get('token_endpoint') == 'https://kc.coulomb.social/token',
'issuer_discovery_changed')
require(isinstance(private.get('human_token'), str) and private['human_token']
and isinstance(private.get('coding_agent_token'), str) and private['coding_agent_token'],
'founder_private_tokens_required')
require(k(['get', 'namespace', 'kube-system', '-o', 'json'])['metadata']['uid'] == CLUSTER,
'cluster_identity_changed')
before = get('secret', 'keycape-config')
deployment = get('deployment', 'keycape')
require(not before['metadata'].get('ownerReferences'), 'controller_owned_config')
require(meta(before) == envelope['config_metadata']
and meta(deployment) == envelope['deployment_metadata']
and canonical(deployment['spec']) == envelope['deployment_spec_sha256'],
'approved_runtime_revision_changed')
raw = base64.b64decode(before['data']['config.yaml'], validate=True).decode()
require(digest(raw.encode()) == envelope['registry_sha256'], 'approved_registry_changed')
updated = base64.b64encode(candidate_config(raw).encode()).decode()
intended_data = dict(before['data'], **{'config.yaml': updated})
candidate = candidate_spec(deployment['spec'])
ready(deployment['spec'])
# Exact GET existence is tested via create (never adopt/delete an existing Secret).
values = {c: secrets.token_urlsafe(48) for c in IDS}
temporary = {'apiVersion': 'v1', 'kind': 'Secret', 'metadata': {'namespace': 'sso', 'name': TEMP},
'type': 'Opaque', 'data': {c: base64.b64encode(v.encode()).decode() for c, v in values.items()}}
patch('secret', before, '/data/config.yaml', updated, dry=True)
patch('deployment', deployment, '/spec', candidate, dry=True)
k(['create', '-f', '/dev/stdin', '--dry-run=server', '-o', 'json'], temporary)
created = None
mutations_attempted = False
began = time.monotonic()
try:
# Set before API call: uncertain response must still trigger reconciliation.
check_deadline()
mutations_attempted = True
created = k(['create', '-f', '/dev/stdin', '-o', 'json'], temporary)
receipt['temporary_secret_uid'] = created['metadata']['uid']
checkpoint()
patch('secret', before, '/data/config.yaml', updated)
patch('deployment', deployment, '/spec', candidate)
ready(candidate)
require(get('secret', 'keycape-config')['data'] == intended_data, 'registry_drift')
require(time.monotonic() - began < 300, 'probe_start_too_late')
# Current admitted agent token stays founder-owned; no existing secret fetched.
original_exchange = probe.exchange
def exchange(post, endpoint, client, secret, scope):
if client == 'codex-railiance-platform':
return private['coding_agent_token']
return original_exchange(post, endpoint, client, secret, scope)
probe.exchange = exchange
supplied = dict(values, **{'codex-railiance-platform': 'founder-held-token'})
def bounded_post(*args, **kwargs):
if not args[0].endswith('/v1/auth/token/revoke-self'):
require(time.monotonic() - began < envelope['maximum_session_seconds'] - 180,
'session_cleanup_reserve_reached')
return transport.post(*args, **kwargs)
def bounded_sleep(seconds):
while seconds > 0:
check_deadline()
require(time.monotonic() - began < envelope['maximum_session_seconds'] - 180,
'session_cleanup_reserve_reached')
part = min(seconds, 3)
time.sleep(part)
seconds -= part
result = probe.run(bounded_post, supplied, 'https://kc.coulomb.social/token',
envelope['bao_addr'], 'keycape-services', 'secrets-engine-openbao',
human_token=private['human_token'], leeway=leeway, sleep=bounded_sleep)
receipt['negative_probe'] = result
checkpoint()
check_deadline()
require(time.monotonic() - began <= envelope['maximum_session_seconds'], 'session_window_exceeded')
require(result['all_refused'], 'negative_proof_incomplete')
finally:
if mutations_attempted:
begin_cleanup()
CLEANING = True
# Never restore over an unrelated edit; keep custody for owner recovery on drift.
now = get('secret', 'keycape-config')
require(now['metadata']['uid'] == before['metadata']['uid'] and
now['data'] in [before['data'], intended_data], 'cleanup_registry_drift')
if now['data'] == intended_data:
patch('secret', now, '/data/config.yaml', before['data']['config.yaml'])
now = get('deployment', 'keycape')
require(now['metadata']['uid'] == deployment['metadata']['uid'] and
now['spec'] in [deployment['spec'], candidate], 'cleanup_deployment_drift')
if now['spec'] == candidate:
patch('deployment', now, '/spec', deployment['spec'])
ready(deployment['spec'])
require(get('secret', 'keycape-config')['data'] == before['data'], 'cleanup_readback_failed')
# No fresh JWT is minted: deleted clients must fail at the issuer.
for client in IDS:
basic = base64.b64encode((client + ':' + values[client]).encode()).decode()
status, body = transport.post('https://kc.coulomb.social/token',
form={'grant_type': 'client_credentials', 'scope': 'openbao:login'},
headers={'Authorization': 'Basic ' + basic})
require(removed_client_denied(status, body),
'removed_client_denial_unconfirmed')
if created is None:
# A timed-out create may have succeeded; compare generated bytes before delete.
observed = get('secret', TEMP)
require(observed.get('data') == temporary['data'], 'temporary_secret_identity_unconfirmed')
created = observed
observed = get('secret', TEMP)
require(observed['metadata']['uid'] == created['metadata']['uid']
and observed.get('data') == temporary['data'], 'temporary_secret_drift')
delete_temporary(observed)
receipt['cleanup_verified'] = True
def main():
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
ap.add_argument('mode', choices=['inspect', 'founder-preflight', 'execute', 'recover'])
ap.add_argument('--envelope')
ap.add_argument('--confirm')
ap.add_argument('--receipt', required=True)
args = ap.parse_args()
receipt = {'proposal_id': PROPOSAL, 'target': TARGET, 'native_accepted': False,
'values_emitted': False, 'cleanup_verified': False}
# Do not truncate or follow a link; protected receipts cannot overwrite credentials.
fd = os.open(args.receipt, os.O_WRONLY | os.O_CREAT | os.O_EXCL | os.O_NOFOLLOW, 0o600)
def checkpoint():
os.lseek(fd, 0, os.SEEK_SET)
os.ftruncate(fd, 0)
os.write(fd, json.dumps(receipt, sort_keys=True, indent=2).encode())
os.fsync(fd)
rc = 1
try:
if args.mode in ['inspect', 'founder-preflight']:
require(k(['get', 'namespace', 'kube-system', '-o', 'json'])['metadata']['uid'] == CLUSTER,
'cluster_identity_changed')
dep = get('deployment', 'keycape')
receipt.update(deployment_metadata=meta(dep), deployment_spec_sha256=canonical(dep['spec']),
image=next(c['image'] for c in dep['spec']['template']['spec']['containers']
if c['name'] == 'keycape'), mode='metadata_only')
if args.mode == 'founder-preflight':
require(args.confirm == 'FOUNDER ATTENDED KEY39 PREFLIGHT', 'founder_attendance_required')
config = get('secret', 'keycape-config')
require(not config['metadata'].get('ownerReferences'), 'controller_owned_config')
raw = base64.b64decode(config['data']['config.yaml'], validate=True).decode()
candidate_config(raw)
candidate_spec(dep['spec'])
require(k(['-n', 'sso', 'get', 'secret', TEMP, '--ignore-not-found', '-o', 'json']) is None,
'temporary_secret_already_exists')
ready(dep['spec'])
receipt.update(config_metadata=meta(config), registry_sha256=digest(raw.encode()),
baseline_ready=True, mode='founder_protected_preflight',
probe_ids_absent=True, probe_env_absent=True, temporary_secret_absent=True)
else:
require(args.envelope is not None, 'approval_envelope_required')
envelope = read_json(Path(args.envelope).read_text())
require(Path(args.envelope).stat().st_mode & 0o022 == 0, 'approval_envelope_writable')
signal.signal(signal.SIGTERM, lambda *_: (_ for _ in ()).throw(Refused('session_interrupted')))
if args.mode == 'recover':
recover(envelope, receipt)
else:
private = read_json(__import__('sys').stdin.read())
execute(envelope, private, receipt, checkpoint=checkpoint)
receipt['negative_and_cleanup_verified'] = True
rc = 0
except Refused as error:
receipt.update(status='incomplete_requires_owner_review', reason=str(error))
except BaseException:
# Fixed outcome only: exception text may contain protected Kubernetes/HTTP data.
receipt['status'] = 'incomplete_requires_owner_review'
finally:
checkpoint()
os.close(fd)
return rc
if __name__ == '__main__':
raise SystemExit(main())