net-kingdom/tools/bounded-execution-run/bx.py
tegwick 646ced3f9e
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
NK-WP-0058-T04 done: bx, four founder commands plus the approval
bx ready / request / run / status (close for emergencies): inputs in a state file, receipts numbered
by the tool, every command safe to repeat and one value-free line. OpenBao steps run as silent
children of the warden platform-admin lane (executor-lanes.py --quiet); run closes the window in the
same child, also on error. Runbook sections 5-6 replaced; pilot-run.sh deleted. 134 tests.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 943911@bnt-lap001
Assistant-Session: fc322940-1c8e-4bed-ab39-86cec99f23a0
2026-11-05 23:45:02 +01:00

308 lines
16 KiB
Python

#!/usr/bin/env python3
"""Founder commands for one bounded-execution run (NK-WP-0058-T04). Each prints one value-free line.
BX="python3 tools/bounded-execution-run/bx.py"
$BX ready admissions/BEA-YYYY-NNNN.yaml # readiness; one platform-admin login (OpenBao status)
$BX request # file the approval; the id goes into the state file
(approve the memo in informed-decision: browser profile of admin, aal2 with OTP)
$BX run # preflight, then window open, run, close; one platform-admin login
$BX status # the run's state and receipts, no login
$BX close # emergency: delete the write role; safe to repeat
Inputs live in a state file (~/.local/state/net-kingdom/bounded-execution/<id>.json), not in shell variables.
The admission named last is the current one; --admission selects another. Receipts are numbered by the tool in
docs/evidence/<date>-<id>/. Each command is safe to repeat: `run` never starts a second run for an admission.
The OpenBao steps run as silent children of `warden access openbao-platform-admin-login --exec`; the window
is closed in the same child, also when the run fails or is interrupted.
--attest names the trust states you attest for the run (default: runtime_secret_trust,runtime_identity_trust).
They are recorded in the state file and the run config, never edited in by hand.
"""
import argparse
import datetime as dt
import hashlib
import json
import os
import re
import subprocess
import sys
import time
from pathlib import Path
import yaml
REPO = Path(__file__).resolve().parents[2]
HOME = Path.home()
STATE_DIR = Path(os.environ.get('BX_STATE_DIR', HOME / '.local/state/net-kingdom/bounded-execution'))
RAPP = Path(os.environ.get('BX_RAPP', REPO.parent / 'rapp-bounded-executor'))
PLATFORM = Path(os.environ.get('BX_PLATFORM', REPO.parent / 'railiance-platform'))
KUBECONFIG = Path(os.environ.get('BX_KUBECONFIG', HOME / '.kube/config-railiance01'))
BAO_ADDR = os.environ.get('BAO_ADDR', 'http://127.0.0.1:18200')
LANE = ['warden', 'access', 'openbao-platform-admin-login', '--exec', '--']
LANES_TOOL = REPO / 'tools/service-binds/executor-lanes.py'
READY_TOOL = REPO / 'tools/bounded-execution-readiness/ready.py'
CCRS = {'write': 'CCR-2026-0058-*.yaml', 'journey': 'CCR-2026-0059-*.yaml'}
DELIVERIES = ('keycape-nk-bind-executor-approval-client', 'bounded-executor-tokens')
ATTEST = 'runtime_secret_trust,runtime_identity_trust'
WARDEN_EXIT = {10: 'login_failed', 11: 'child_failed', 12: 'child_output', 13: 'revoke_unconfirmed',
14: 'cleanup_failed'}
class Runner:
"""Every outside command goes through here; tests replace it."""
def run(self, argv, env=None, timeout=900):
full = {**os.environ, **(env or {})}
done = subprocess.run([str(a) for a in argv], capture_output=True, env=full, timeout=timeout)
return done.returncode, done.stdout.decode(errors='replace')
def sleep(self, seconds):
time.sleep(seconds)
def kubectl():
return f'kubectl --kubeconfig {KUBECONFIG}'
def json_blocks(text):
"""The value-free JSON results in a log: one-line objects and the executor's indented result blocks."""
out = []
for block in re.findall(r'^\{\n.*?\n\}$', text, re.M | re.S) + re.findall(r'^\{.*\}$', text, re.M):
try:
out.append(json.loads(block))
except ValueError:
pass
return out
class Bx:
def __init__(self, runner=None, now=None):
self.r = runner or Runner()
self.now = now or (lambda: dt.datetime.now(dt.timezone.utc))
# ------------------------------------------------------------------ state and receipts
def state_path(self, admission_id):
return STATE_DIR / f'{admission_id}.json'
def load(self, admission=None):
if admission:
doc = yaml.safe_load(Path(admission).read_text())
sid = doc['spec']['id']
path = self.state_path(sid)
if path.exists():
return json.loads(path.read_text())
evidence = REPO / 'docs/evidence' / f"{self.now():%Y-%m-%d}-{sid.lower()}"
return {'admission_id': sid, 'admission': str(Path(admission).resolve()), 'evidence': str(evidence),
'approval_id': None, 'attest': None, 'run': None}
current = STATE_DIR / 'current'
if not current.exists():
raise SystemExit(self.line({'status': 'refused', 'reason': 'no_admission', 'next': 'bx ready ADMISSION'}))
return json.loads(self.state_path(current.read_text().strip()).read_text())
def save(self, state):
STATE_DIR.mkdir(parents=True, exist_ok=True)
path = self.state_path(state['admission_id'])
path.write_text(json.dumps(state, indent=2, sort_keys=True) + '\n')
(STATE_DIR / 'current').write_text(state['admission_id'] + '\n')
def receipt(self, state, name):
folder = Path(state['evidence'])
folder.mkdir(parents=True, exist_ok=True)
numbers = [int(p.name[:2]) for p in folder.glob('[0-9][0-9]-*')]
return folder / f'{max(numbers, default=0) + 1:02d}-{name}.json'
def write(self, path, data):
path.write_text(json.dumps(data, indent=2, sort_keys=True) + '\n')
return path
def config(self, state):
"""The run config: the rapp's pilot config with the attested trust states. Non-secret."""
cfg = json.loads((RAPP / 'examples/config.pilot.json').read_text())
cfg['trust_satisfied'] = list(state['attest'])
path = STATE_DIR / f"{state['admission_id']}.config.json"
path.write_text(json.dumps(cfg, indent=2) + '\n')
return path
@staticmethod
def line(data):
return json.dumps(data, separators=(', ', ': '))
def lane(self, child):
"""Run a silent child under one platform-admin login. The child gets an isolated HOME from warden, so every
path it needs is passed as an absolute path here."""
env = {'BAO_ADDR': BAO_ADDR, 'VAULT_ADDR': BAO_ADDR, 'PYTHONWARNINGS': 'ignore', 'BX_STATE_DIR': STATE_DIR,
'BX_RAPP': RAPP, 'BX_PLATFORM': PLATFORM, 'BX_KUBECONFIG': KUBECONFIG, 'NK_PLATFORM_ROOT': PLATFORM}
code, _ = self.r.run(LANE + child, env={k: str(v) for k, v in env.items()})
return code
# ------------------------------------------------------------------ commands
def ready(self, admission, attest):
state = self.load(admission)
state['attest'] = state['attest'] or attest.split(',')
self.save(state)
rec = self.receipt(state, 'readiness')
self.r.run(['python3', READY_TOOL, '--admission', state['admission'],
'--approval-id', state['approval_id'] or 'none', '--receipt', rec])
agent = (json.loads(rec.read_text()) if rec.exists()
else {'agent_checks_pass': False, 'failures': ['no_receipt']})
custody = {}
for name in DELIVERIES:
code, out = self.r.run(kubectl().split() + ['-n', 'sso', 'get', 'externalsecret', name, '-o',
'jsonpath={.status.conditions[?(@.type=="Ready")].status}'])
custody[name] = code == 0 and out.strip() == 'True'
self.write(self.receipt(state, 'custody'), {'action': 'custody-delivery', 'ready': custody,
'values_recorded': False})
status = self.receipt(state, 'lanes-status')
warden = self.lane(['python3', LANES_TOOL, 'status', '--receipt', status, '--quiet'])
lanes = json.loads(status.read_text()) if status.exists() else {}
failures = list(agent.get('failures', [])) + [f'custody:{n}' for n, ok in custody.items() if not ok]
if not lanes.get('ready_for_window'):
failures.append('openbao:' + (lanes.get('reason') or WARDEN_EXIT.get(warden, 'not_ready_for_window')))
state['ready'] = {'at': f'{self.now():%Y-%m-%dT%H:%M:%SZ}', 'failures': failures}
self.save(state)
nxt = 'bx run' if state['approval_id'] else 'bx request'
return self.line({'ready': not failures, 'admission': state['admission_id'], 'failures': failures,
'next': nxt if not failures else 'fix the failures, then bx ready again'})
def request(self):
state = self.load()
if state['approval_id']:
return self.line({'approval_id': state['approval_id'], 'status': 'already_requested',
'next': 'approve as admin (aal2), then bx run'})
code, out = self.r.run(['make', '-C', RAPP, 'request', f"ADMISSION={state['admission']}",
f'CONFIG={self.config(state)}', f'KUBECTL={kubectl()}'])
result = next((b for b in reversed(json_blocks(out)) if 'outcome' in b), {})
self.write(self.receipt(state, 'request'), {**result, 'exit': code})
if result.get('approval_id'):
state['approval_id'] = result['approval_id']
self.save(state)
return self.line({'approval_id': result.get('approval_id'), 'outcome': result.get('outcome'),
'next': 'open the memo as admin (aal2, fresh OTP), approve, then bx run'
if result.get('outcome') == 'presented' else 'bx request again (idempotent)'})
def run(self):
state = self.load()
if state.get('run') and state['run'].get('started'):
return self.line({**self.summary(state), 'status': 'already_run'})
if not state['approval_id']:
return self.line({'status': 'refused', 'reason': 'no_approval', 'next': 'bx request'})
self.config(state)
code = self.lane(['python3', Path(__file__).resolve(), '_run-inner', '--state',
self.state_path(state['admission_id'])])
state = json.loads(self.state_path(state['admission_id']).read_text())
if code and not (state.get('run') or {}).get('finished'):
state['run'] = {**(state.get('run') or {}), 'warden': WARDEN_EXIT.get(code, f'exit_{code}')}
self.save(state)
return self.line(self.summary(state))
def run_inner(self, state_file):
"""The silent lane child: preflight, then window open, run, poll, and close in `finally`. Prints nothing."""
state = json.loads(Path(state_file).read_text())
cfg = STATE_DIR / f"{state['admission_id']}.config.json"
k = kubectl()
run = state['run'] = {'started': False, 'receipts': []}
def note(path):
run['receipts'].append(Path(path).name)
self.save(state)
_, out = self.r.run(['make', '-C', RAPP, 'preflight', f"ADMISSION={state['admission']}",
f"APPROVAL_ID={state['approval_id']}", f'CONFIG={cfg}', f'KUBECTL={k}'])
report = next((b for b in reversed(json_blocks(out)) if b.get('mode') == 'preflight-only'),
{'ready': False, 'failures': ['preflight_no_report']})
note(self.write(self.receipt(state, 'preflight'), report))
if not report.get('ready'):
run.update(outcome='not_started', reason='preflight_not_ready', failures=report.get('failures'))
return self.save(state)
digests = {}
for lane, pattern in CCRS.items():
files = sorted((PLATFORM / 'credential-change-requests').glob(pattern))
digests[lane] = hashlib.sha256(files[0].read_bytes()).hexdigest()
opened = self.receipt(state, 'window-open')
try:
self.r.run(['python3', LANES_TOOL, 'window-open', '--admission', state['admission'],
'--write-ccr-sha256', digests['write'], '--journey-ccr-sha256', digests['journey'],
'--receipt', opened, '--quiet'])
note(opened)
if json.loads(opened.read_text()).get('status') != 'window_opened':
run.update(outcome='not_started', reason='window_not_opened')
return
run['started'] = True
self.save(state)
code, _ = self.r.run(['make', '-C', RAPP, 'run', f"ADMISSION={state['admission']}",
f"APPROVAL_ID={state['approval_id']}", f'CONFIG={cfg}', f'KUBECTL={k}'])
if code:
run.update(outcome='not_started', reason='job_not_created')
return
job = 'bounded-executor-' + state['admission_id'].lower()
budget = yaml.safe_load(Path(state['admission']).read_text())['spec']['budget']['wall_time_seconds']
for _ in range(int(budget / 5) + 60):
_, st = self.r.run(k.split() + ['-n', 'sso', 'get', f'job/{job}', '-o',
'jsonpath={.status.succeeded}{.status.failed}'])
if st.strip():
break
self.r.sleep(5)
_, logs = self.r.run(k.split() + ['-n', 'sso', 'logs', f'job/{job}'])
result = next((b for b in reversed(json_blocks(logs)) if 'outcome' in b),
{'outcome': 'unknown', 'reason': 'no_result_in_log'})
note(self.write(self.receipt(state, 'result'), result))
run.update(outcome=result.get('outcome'), reason=result.get('reason'), run_id=result.get('run_id'))
finally:
closed = self.receipt(state, 'window-close')
self.r.run(['python3', LANES_TOOL, 'window-close', '--admission', state['admission'],
'--receipt', closed, '--quiet'])
if closed.exists():
note(closed)
run['window_closed'] = json.loads(closed.read_text()).get('status') == 'window_closed'
run['finished'] = True
self.save(state)
def summary(self, state):
run = state.get('run') or {}
return {'admission': state['admission_id'], 'approval_id': state['approval_id'],
'outcome': run.get('outcome'), 'reason': run.get('reason'), 'window_closed': run.get('window_closed'),
'warden': run.get('warden'), 'error': run.get('error'), 'receipts': len(run.get('receipts', [])),
'evidence': os.path.relpath(state['evidence'], REPO)}
def status(self):
return self.line(self.summary(self.load()))
def close(self):
state = self.load()
rec = self.receipt(state, 'window-close')
code = self.lane(['python3', LANES_TOOL, 'window-close', '--admission', state['admission'], '--receipt', rec,
'--quiet'])
closed = json.loads(rec.read_text()) if rec.exists() else {}
return self.line({'status': closed.get('status', 'failed'), 'reason': closed.get('reason'),
'warden': WARDEN_EXIT.get(code) if code else None})
def main(argv=None, bx=None):
p = argparse.ArgumentParser(description=__doc__, formatter_class=argparse.RawDescriptionHelpFormatter)
p.add_argument('command', choices=['ready', 'request', 'run', 'status', 'close', '_run-inner'])
p.add_argument('admission', nargs='?')
p.add_argument('--attest', default=ATTEST)
p.add_argument('--state', help=argparse.SUPPRESS)
a = p.parse_args(argv)
bx = bx or Bx()
if a.command == '_run-inner': # a silent lane child: any output would fail the lane, so record, never print
try:
bx.run_inner(a.state)
except Exception as error:
state = json.loads(Path(a.state).read_text())
state['run'] = {**(state.get('run') or {}), 'error': type(error).__name__, 'finished': True}
Path(a.state).write_text(json.dumps(state, indent=2, sort_keys=True) + '\n')
return 0
if a.command == 'ready':
if not a.admission:
p.error('ready takes the admission file')
print(bx.ready(a.admission, a.attest))
return 0
if a.admission:
bx.save(bx.load(a.admission))
print({'request': bx.request, 'run': bx.run, 'status': bx.status, 'close': bx.close}[a.command]())
return 0
if __name__ == '__main__':
sys.exit(main())