informed-decision/docs/evidence/2026-10-11-purpose-image-release/preflight.py
tegwick e0359bcb6c Prepare purpose image release with bounded custody protocol and owner reviews
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
2026-10-11 03:54:35 +02:00

25 lines
7.2 KiB
Python

"""Read-only refresh; exact original capture remains immutable; never execute cutover."""
import argparse,hashlib,json,subprocess,sys
from pathlib import Path
if sys.flags.optimize:
raise SystemExit("optimized interpreter refused before source/transport execution")
ROOT=Path(__file__).resolve().parent
p=argparse.ArgumentParser();p.add_argument('--receipt-output',type=Path,required=True);p.add_argument('--source-root',type=Path,default=Path('/home/worsch/informed-decision'));a=p.parse_args()
out=a.receipt_output.resolve()
if not a.receipt_output.is_absolute() or out==ROOT or ROOT in out.parents or out==a.source_root.resolve() or a.source_root.resolve() in out.parents or out.exists():
raise SystemExit('unique execution receipt must be outside the sealed packet')
inputs=json.loads((ROOT/'preflight-inputs.json').read_text())
for relative,digest in inputs['packet_files'].items():
path=ROOT/relative
if path.is_symlink() or hashlib.sha256(path.read_bytes()).hexdigest()!=digest:raise SystemExit('sealed helper/input bytes changed')
for relative,digest in inputs['owner_source_files'].items():
path=a.source_root/relative
if path.is_symlink() or hashlib.sha256(path.read_bytes()).hexdigest()!=digest:raise SystemExit('owner source bytes changed')
from change_guard import transport_result
program='import subprocess,json,hashlib,datetime,sys,copy,re\nif sys.flags.optimize:raise RuntimeError("optimized interpreter refused")\ncandidate=json.loads(CANDIDATE_LITERAL)\nsealed_dependencies=json.loads(DEPENDENCIES_LITERAL)\nsealed_baseline=json.loads(SEALED_LITERAL)\nexec(GUARD_LITERAL)\ndef run(args,data=None):\n p=subprocess.run(args,input=data,text=True,capture_output=True)\n if p.returncode: raise ValueError(\'read-only command failed: \'+args[1]+\' \'+args[2])\n return p.stdout\nlive=json.loads(run([\'kubectl\',\'get\',\'deployment\',\'informed-decision\',\'-n\',\'informed-decision\',\'-o\',\'json\']))\ncm=json.loads(run([\'kubectl\',\'get\',\'configmap\',\'informed-decision-runtime-6c221878d051\',\'-n\',\'informed-decision\',\'-o\',\'json\']))\npvc=json.loads(run([\'kubectl\',\'get\',\'pvc\',\'informed-decision-data\',\'-n\',\'informed-decision\',\'-o\',\'json\']))\ncheck_dependencies(cm,pvc,sealed_dependencies)\ncheck_current(live,sealed_baseline)\nspec=live[\'spec\']; cs=spec[\'template\'][\'spec\'][\'containers\'];assert len(cs)==1 and cs[0][\'name\']==\'informed-decision\'\nexpected_env={\'INFD_KEYCAPE_ISSUER\':\'https://kc.coulomb.social\',\'INFD_CONTAINER_CONFIG\':\'/configuration/runtime.json\'}\nassert cs[0].get(\'env\')==[{\'name\':\'INFD_KEYCAPE_ISSUER\',\'value\':expected_env[\'INFD_KEYCAPE_ISSUER\']},{\'name\':\'INFD_CONTAINER_CONFIG\',\'value\':expected_env[\'INFD_CONTAINER_CONFIG\']}]\nassert cs[0][\'image\']==\'forgejo.coulomb.social/coulomb/informed-decision@sha256:7f5c6cb29c9f70a026bfe30e72934274ddc69261676cf6d476f81dd32812d173\'\nassert spec[\'replicas\']==1 and spec[\'strategy\']=={\'type\':\'Recreate\'}\nassert next(v for v in spec[\'template\'][\'spec\'][\'volumes\'] if v[\'name\']==\'configuration\')[\'configMap\'][\'name\']==\'informed-decision-runtime-6c221878d051\'\nassert live[\'status\'].get(\'readyReplicas\')==1 and live[\'status\'].get(\'updatedReplicas\')==1\nsealed={\'apiVersion\':live[\'apiVersion\'],\'kind\':live[\'kind\'],\'metadata\':{k:copy.deepcopy(v) for k,v in live[\'metadata\'].items() if k not in (\'resourceVersion\',\'generation\',\'creationTimestamp\',\'managedFields\')},\'spec\':copy.deepcopy(spec)}\nfor key in (\'kubectl.kubernetes.io/last-applied-configuration\',\'deployment.kubernetes.io/revision\'):sealed[\'metadata\'].get(\'annotations\',{}).pop(key,None)\nadmitted=json.loads(run([\'kubectl\',\'apply\',\'--dry-run=server\',\'-f\',\'-\',\'-o\',\'json\'],json.dumps(candidate)))\ncheck_admitted(admitted,sealed_baseline)\napp=json.loads(run([\'kubectl\',\'get\',\'application\',\'informed-decision\',\'-n\',\'argocd\',\'-o\',\'json\']))\nassert app[\'spec\'][\'source\'][\'path\']==\'deploy/lifecycle\' and not app[\'spec\'].get(\'syncPolicy\',{}).get(\'automated\')\nargo={\'uid\':app[\'metadata\'][\'uid\'],\'repoURL\':app[\'spec\'][\'source\'][\'repoURL\'],\'targetRevision\':app[\'spec\'][\'source\'][\'targetRevision\'],\'path\':app[\'spec\'][\'source\'][\'path\'],\'destination\':app[\'spec\'][\'destination\'],\'automated\':False,\'sync\':app.get(\'status\',{}).get(\'sync\'),\'health\':app.get(\'status\',{}).get(\'health\')}\nexpected_argo=json.loads(ARGO_LITERAL)\nfor key in (\'uid\',\'repoURL\',\'targetRevision\',\'path\',\'destination\',\'automated\'):\n assert argo[key]==expected_argo[key]\nassert argo[\'health\'][\'status\']==\'Healthy\'\ndiff=subprocess.run([\'kubectl\',\'diff\',\'-f\',\'-\'],input=json.dumps(candidate),text=True,capture_output=True);assert diff.returncode in (0,1)\n# Diff can contain only nonsecret Deployment references; preserve digest rather than raw stdout.\nnode=run([\'kubectl\',\'describe\',\'node\']);allocated=re.search(r\'Allocated resources:.*?CPU Requests|Allocated resources:\',node,re.S)\nsection=node.split(\'Allocated resources:\')[1].split(\'Events:\')[0] if \'Allocated resources:\' in node else \'\'\nnodes=json.loads(run([\'kubectl\',\'get\',\'nodes\',\'-o\',\'json\']))[\'items\'];assert len(nodes)==1\nalloc=nodes[0][\'status\'][\'allocatable\'];cpu=alloc[\'cpu\'];cpu_m=int(cpu[:-1]) if cpu.endswith(\'m\') else int(cpu)*1000\nrequested=int(re.search(r\'cpu\\s+(\\d+)m\',section).group(1));assert requested<=cpu_m\nreceipt={\'node_allocatable_cpu_m\':cpu_m,\'node_requested_cpu_m\':requested,\'captured_at\':datetime.datetime.now(datetime.timezone.utc).isoformat(),\'native_workload_changed\':False,\'native_backup_restore_executed\':False,\'argo\':argo,\'native_dependencies_checked\':True,\'configmap_uid\':cm[\'metadata\'][\'uid\'],\'pvc_uid\':pvc[\'metadata\'][\'uid\'],\'live_ready_replicas\':1,\'admitted_uid\':admitted[\'metadata\'][\'uid\'],\'server_dry_run_passed\':True,\'admitted_spec_exactly_live_plus_image\':True,\'client_diff_exit\':diff.returncode,\'client_diff_sha256\':hashlib.sha256(diff.stdout.encode()).hexdigest(),\'node_allocated_resources\':section.strip(),\'all_checks_pass\':True}\nprint(json.dumps(receipt))\n'
for marker,value in [('DEPENDENCIES_LITERAL',(ROOT/'sealed-native-dependencies.json').read_text()),('CANDIDATE_LITERAL',(ROOT/'candidate-deployment.json').read_text()),('SEALED_LITERAL',(ROOT/'sealed-live-deployment.json').read_text()),('GUARD_LITERAL',(ROOT/'change_guard.py').read_text()),('ARGO_LITERAL',json.dumps(json.loads((ROOT/'native-preflight.json').read_text())['argo']))]:
program=program.replace(marker,repr(value))
program='import traceback,json\ntry:\n'+''.join(' '+line+'\n' for line in program.splitlines())+"except Exception as error:\n print(json.dumps({'all_checks_pass':False,'exception_type':type(error).__name__,'exception_line':traceback.extract_tb(error.__traceback__)[-1].lineno}))\n"
r=subprocess.run(['ssh','railiance01','python3 -'],input=program,text=True,capture_output=True)
result=transport_result(r.returncode,r.stdout);result['sealed_preflight_inputs_sha256']=hashlib.sha256((ROOT/'preflight-inputs.json').read_bytes()).hexdigest();result['fresh_execution_receipt']=True
out.write_text(json.dumps(result,indent=2)+'\n');print(json.dumps(result,indent=2));sys.exit(0 if result.get('all_checks_pass') is True else 1)