user-engine/tools/run_approved_catalogue_bootstrap.py
tegwick c89614ec81
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
Account journey acceptance / journeys (push) Successful in 33s
Prepare source-bound one-use catalogue maintenance exception
Assistant: codex
Assistant-Model: gpt-6.1-sol
Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
2026-10-11 03:29:45 +02:00

62 lines
4.2 KiB
Python

"""Prepared supervisor-only transport. NEVER run before founder exception approval.
No credentials leave the workload. Source/grant are delivered only on stdin.
"""
import argparse,base64,hashlib,json,os,stat,subprocess,sys
from pathlib import Path
def main():
p=argparse.ArgumentParser(description=__doc__)
p.add_argument('--executor',type=Path,required=True)
p.add_argument('--executor-sha256',required=True)
p.add_argument('--grant-file',type=Path,required=True)
p.add_argument('--grant-sha256',required=True)
p.add_argument('--expected-pod-uid',required=True)
p.add_argument('--mode',choices=['dry-run','apply','rollback'],default='dry-run')
a=p.parse_args()
try:
st=a.grant_file.lstat()
if not stat.S_ISREG(st.st_mode) or st.st_uid!=os.getuid() or stat.S_IMODE(st.st_mode)!=0o600 or st.st_size>8192:raise ValueError('private grant required')
source=a.executor.read_bytes();grant=json.loads(a.grant_file.read_text())
sha=lambda b:hashlib.sha256(b).hexdigest()
canonical=lambda x:json.dumps(x,sort_keys=True,separators=(',',':')).encode()
if sha(source)!=a.executor_sha256 or sha(canonical(grant))!=a.grant_sha256:raise ValueError('source/grant mismatch')
packet={'source':base64.b64encode(source).decode(),'executor_sha256':a.executor_sha256,'grant':grant,'grant_sha256':a.grant_sha256,'mode':a.mode}
native="""
import base64,hashlib,json,os,sys
payload=json.loads(base64.b64decode('__PACKET__'))
saved=os.dup(1);null=os.open(os.devnull,os.O_WRONLY);os.dup2(null,1);os.dup2(null,2)
try:
source=base64.b64decode(payload['source'])
if hashlib.sha256(source).hexdigest()!=payload['executor_sha256']:raise ValueError('source differs')
ns={'__name__':'supervised_catalogue_maintenance'};exec(compile(source,'<reviewed-maintenance-executor>','exec'),ns)
import psycopg
from user_engine.adapters.flex_auth import FlexAuthHTTPAdapter
ordinary=FlexAuthHTTPAdapter(base_url=os.environ['USER_ENGINE_FLEX_AUTH_URL'],bearer_token_file=os.environ['USER_ENGINE_FLEX_AUTH_TOKEN_FILE'],timeout_seconds=3)
with psycopg.connect(os.environ['USER_ENGINE_DATABASE_URL']) as conn:
result=ns['execute'](conn,ordinary,payload['grant'],expected_grant_sha256=payload['grant_sha256'],actual_executor_sha256=payload['executor_sha256'],mode=payload['mode'])
except Exception:result={'result':'refused-or-rolled-back','raw_output_suppressed':True}
os.dup2(saved,1);os.close(saved);os.close(null);print(json.dumps(result,sort_keys=True))
""".replace('__PACKET__',base64.b64encode(canonical(packet)).decode())
remote="""
import base64,json,subprocess,sys
r=subprocess.run(['kubectl','get','pods','-n','user-engine','-l','app.kubernetes.io/name=user-engine','-o','json'],capture_output=True,text=True)
try:
pods=[p for p in json.loads(r.stdout)['items'] if p['metadata']['uid']=='__UID__' and p.get('status',{}).get('phase')=='Running' and any(c['type']=='Ready' and c['status']=='True' for c in p.get('status',{}).get('conditions',[]))]
if r.returncode or len(pods)!=1:raise ValueError('fixed pod not ready')
pod=pods[0];portal=[c for c in pod['spec']['containers'] if c['name']=='portal']
if len(portal)!=1 or portal[0]['image']!='forgejo.coulomb.social/coulomb/user-engine@sha256:f239bbf332b8eb87320c86390fddca1dcb4f7c628a7af75e79dee8058d446a7b':raise ValueError('source runtime differs')
r=subprocess.run(['kubectl','exec','-i','-n','user-engine',pod['metadata']['name'],'-c','portal','--','python3','-'],input=base64.b64decode('__NATIVE__'),capture_output=True)
out=json.loads(r.stdout)
if r.returncode:raise ValueError('exec failure')
except Exception:out={'result':'refused-or-rolled-back','raw_output_suppressed':True}
print(json.dumps(out,sort_keys=True))
""".replace('__UID__',a.expected_pod_uid).replace('__NATIVE__',base64.b64encode(native.encode()).decode())
import uuid
uuid.UUID(a.expected_pod_uid) # only UUID reaches the fixed remote literal
r=subprocess.run(['ssh','railiance01','python3 -'],input=remote,text=True,capture_output=True)
out=json.loads(r.stdout)
if r.returncode:raise ValueError('transport failure')
except Exception:out={'result':'refused-or-rolled-back','raw_output_suppressed':True}
print(json.dumps(out,sort_keys=True))
return 0 if out.get('result') in ('created','no-change','rolled-back') else 2
if __name__=='__main__':raise SystemExit(main())