"""Silent attended provisioning of the separate create-only T03 requester.""" import base64,copy,hashlib,importlib.util,json,os,secrets,sys,time from pathlib import Path from datetime import datetime,timezone import yaml ROOT=Path('/home/worsch/railiance-platform') sys.path.insert(0,str(ROOT/'scripts')) from state_hub_preflight_lane import command,bao,data,assert_cluster,LaneError from keycape_approval_custody import require,read_optional,BOUNDARY KUBE=['kubectl','--kubeconfig','/home/worsch/.kube/config-railiance01'] KV='platform/data/workloads/secrets-engine/approval-requester' META='platform/metadata/workloads/secrets-engine/approval-requester' CLIENT=json.loads(Path('/home/worsch/key-cape/docs/t03-requester-registration.json').read_text()) RECEIPT=ROOT/'docs/evidence/2026-09-14-t03-requester-provision.json' def load(name,path): spec=importlib.util.spec_from_file_location(name,path); m=importlib.util.module_from_spec(spec);spec.loader.exec_module(m);return m rollout=load('requester_rollout','/home/worsch/net-kingdom/sso-mfa/k8s/keycape/approval-clients-rollout.py') rollout.IDS=('secrets-engine-requester',) def run(receipt): require(Path.home().parent.name=='.warden-attended-login' and not os.getenv('BAO_TOKEN') and not os.getenv('VAULT_TOKEN'),'attended_envelope_required') assert_cluster(KUBE) identity=data(bao(['token','lookup','-format=json']))['data'] require('platform-admin' in identity['policies'] and 'root' not in identity['policies'],'attended_operator_required') require(CLIENT['clientId']=='secrets-engine-requester' and CLIENT['allowedScopes']==['approval:create'] and CLIENT['serviceSubject']=='secrets-engine' and CLIENT['audience']=='approval-engine' and CLIENT['tenant']=='tenant:platform','requester_contract_drift') require(read_optional(META) is None,'existing_requester_custody_requires_reconciliation') for ref in ('CCR-2026-0024','CCR-2026-0025'): command(['python3',str(ROOT/'scripts/credential-change.py'),'applier-dry-run',ref,'--json']) secret=rollout.get(KUBE,'secret','keycape-config') deployment=rollout.get(KUBE,'deployment','keycape') config=rollout.replacement(secret,[CLIENT]) spec=copy.deepcopy(deployment['spec']) require(spec.get('replicas',1)==1 and spec['strategy']['type']=='Recreate','single_recreate_keycape_required') container=next(c for c in spec['template']['spec']['containers'] if c['name']=='keycape') image=container['image']; require('@sha256:' in image,'pinned_keycape_image_required') env_name='KEYCAPE_SECRETS_ENGINE_REQUESTER_CLIENT_SECRET' require(not any(e['name']==env_name for e in container.setdefault('env',[])),'existing_requester_env') container['env'].append({'name':env_name,'valueFrom':{'secretKeyRef':{'name':'keycape-secrets-engine-requester-client','key':'client-secret'}}}) rollout.patch_object(KUBE,'secret',secret,'/data/config.yaml',config,dry=True) rollout.patch_object(KUBE,'deployment',deployment,'/spec',spec,dry=True) receipt['phase']='metadata_preflight_passed' boundary=read_optional(BOUNDARY); require(boundary is not None,'agent_boundary_required') additions=''.join('path "'+p+'" { capabilities = ["deny"] }\n' for p in (KV,META)) require(all('"'+p+'"' not in boundary['policy'] for p in (KV,META)),'boundary_path_requires_reconciliation') bao(['write',BOUNDARY,'-'],payload={'policy':boundary['policy']+'\n'+additions}) require(read_optional(BOUNDARY)['policy']==boundary['policy']+'\n'+additions,'boundary_readback_failed') for ref in ('CCR-2026-0024','CCR-2026-0025'): command(['python3',str(ROOT/'scripts/credential-change.py'),'applier-apply',ref,'--actor','operator via attended T03 requester custody session','--confirm','DELEGATED APPLY '+ref,'--quiet']) receipt['phase']='reader_roles_applied' result=data(bao(['write','-format=json',KV,'-'],payload={'options':{'cas':0},'data':{'CLIENT_SECRET':secrets.token_urlsafe(48)}})) require(result['data']['version']==1,'initial_version_mismatch') receipt.update(phase='custody_seeded',kv_version=1,request_id=result.get('request_id')) RECEIPT.write_text(json.dumps(receipt,indent=2)+'\n') command(KUBE+['apply','-f',str(ROOT/'argocd/platform-addons/openbao-secretstore/t03-requester.yaml')]) deadline=time.monotonic()+90 while time.monotonic()