railiance-platform/tests/test_flex_auth_signer_native.py
codex 20db368aee
All checks were successful
CCR intake gate / gate (push) Successful in 13s
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 1s
RPF-WP-0035-T14: flex-auth signer custody founder gate, runbook and review dispositions
- CCR-2026-0050: record secrets-engine-owner approval (two receipt conditions)
  and platform runbook review; link founder decision 18731e84.
- Attended creation runbook with preconditions, rollback and negatives.
- Warden routing receipt: openbao-platform-admin-login / oidc_login now selected.
- Native adapter: owner-review digest excludes expires_at so reviews can precede
  the 120 s window (close-down checklist row 27).
Nothing generated, written or applied.

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

Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 809600@bnt-lap001
Assistant-Session: 40ba228f-c8a0-4ec9-bb29-3129951afdc4
2026-10-21 01:24:45 +02:00

346 lines
22 KiB
Python

"""Actual disposable KV effects through native production state machine.
Kubernetes, attended identity and owner dispositions are explicitly synthetic
fixture inputs; no production authority/identity/custody claim follows.
"""
from copy import deepcopy
from datetime import datetime,timedelta,timezone
import hashlib
import json
import os
from pathlib import Path
import shutil
import sys
import yaml
import pytest
sys.path.insert(0,str(Path(__file__).resolve().parents[1]/'scripts'))
from test_task_execution_native_fixture import bao_dev
import flex_auth_signer_native as m
from task_execution_journal import Refused
@pytest.fixture
def native(bao_dev,tmp_path,monkeypatch):
origin,token,call,process=bao_dev
assert call('POST','sys/mounts/platform',{'type':'kv','options':{'version':'2'}})[0] in {200,204}
source=tmp_path/'source';source.mkdir()
for name in [*m.SOURCE_FILES,m.CCR,m.PLAN,'openbao/policies/workload-kv-read-flex-auth-envelope-signing.hcl']:
p=source/name;p.parent.mkdir(parents=True,exist_ok=True);shutil.copyfile(m.ROOT/name,p)
ccr=yaml.safe_load((source/m.CCR).read_text());ccr['status']='approved';ccr['openbao']['auth']['bound_claims_confirmed']=True
(source/m.CCR).write_text(yaml.safe_dump(ccr,sort_keys=False))
plan=json.loads((source/m.PLAN).read_text());plan['bootstrap']['kid']='synthetic-native-kid';plan['receipts']['directory']=str(tmp_path/'private');(source/m.PLAN).write_text(json.dumps(plan))
monkeypatch.setattr(m,'ROOT',source)
directory=tmp_path/'private';directory.mkdir(mode=0o700)
image='forgejo.coulomb.social/coulomb/flex-auth@sha256:'+'1'*64
dep={'metadata':{'uid':'dep','generation':1},'spec':{'replicas':0,'template':{'spec':{'serviceAccountName':m.NAME,
'containers':[{'image':image,'args':['serve','--caller-auth-mode','enforce','--caller-audience','flex-auth','--caller-binding','secrets-engine=system:serviceaccount:secrets-engine:secrets-engine','--envelope-signing-key-file','/var/run/secrets/decision-envelope-signing/seed','--envelope-signing-kid','synthetic-native-kid'],
'volumeMounts':[{'name':'flex-auth-envelope-signing','mountPath':'/var/run/secrets/decision-envelope-signing','readOnly':True}]}],
'volumes':[{'name':'flex-auth-envelope-signing','secret':{'secretName':m.SECRET,'defaultMode':288,'items':[{'key':'seed','path':'seed'}]}}]}}},'status':{'observedGeneration':1,'replicas':0}}
class IO:
def __init__(self):
self.calls=[];self.dep=deepcopy(dep);self.pods=[];self.hpas=[];self.rs=[];self.cluster=m.CLUSTER
self.entity='11111111-1111-1111-1111-111111111111';self.backend=m.BAO_CLUSTER;self.root=False;self.role_drift=False;self.lost=False;self.denied=False;self.pod_on_recheck=False;self.fences=0
def bao(self,args,payload=None,allowed=(0,)):
self.calls.append(('bao',tuple(args)))
if args[0]=='status':return 0,{'cluster_id':self.backend,'sealed':False}
if args[:2]==['token','lookup']:return 0,{'data':{'policies':['root'] if self.root else ['platform-admin'],'path':'auth/netkingdom/login/x','entity_id':self.entity,'id':token}}
if args[0]=='audit':return 0,{'file/':{}}
if args[-1].startswith('sys/policies/acl/'):
return 0,{'data':{'policy':(source/'openbao/policies/workload-kv-read-flex-auth-envelope-signing.hcl').read_text()}}
if args[-1].startswith('auth/kubernetes/role/'):
return 0,{'data':{'bound_service_account_names':['foreign'] if self.role_drift else ['flex-auth-envelope-signing-eso'],'bound_service_account_namespaces':['flex-auth'],'bound_service_account_namespace_selector':'','audience':'openbao','token_policies':['workload-kv-read-flex-auth-envelope-signing'],'token_ttl':900,'token_max_ttl':900,'token_explicit_max_ttl':900,'token_no_default_policy':True,'token_period':0,'token_num_uses':0,'token_bound_cidrs':[]}}
raise AssertionError('unexpected fixed API')
def kube(self,resource,name=None):
self.calls.append(('kube',resource,name))
if resource=='namespace':return {'metadata':{'uid':self.cluster}}
if resource=='deployment':
self.fences+=1
if self.pod_on_recheck and self.fences>=3:self.pods=[{'spec':{'serviceAccountName':m.NAME}}]
return deepcopy(self.dep)
return {'items':deepcopy({'pods':self.pods,'hpa':self.hpas,'replicasets':self.rs}[resource])}
def http(self,method,path,body=None):
self.calls.append(('http',method,path))
if self.denied and path in {m.PATH,m.PATH+'?version=1'} and method=='GET':return 403,{'errors':['secret backend detail']}
result=call(method,path,body)
if self.lost and method=='POST' and path==m.PATH:raise OSError('secret response lost')
return result
io=IO()
c={'schema':'railiance-platform.signer-native-admission.v1','action':'bootstrap','operation_id':'synthetic-native-operation','kid':'synthetic-native-kid',
'expires_at':(datetime.now(timezone.utc)+timedelta(seconds=100)).isoformat(),'founder_entity_id':io.entity,
'ccr_sha256':m.digest((source/m.CCR).read_bytes()),'source_bundle':{n:m.digest((source/n).read_bytes()) for n in m.SOURCE_FILES},
'bindings':{k:'sha256:'+'2'*64 for k in m.BINDINGS},'producer_image':image,'caller_binding':'secrets-engine=system:serviceaccount:secrets-engine:secrets-engine',
'deployment_projection_sha256':m.digest(m.encoded(m.deployment_projection(dep))),
'authority':'founder-attended-exact-source-scope; no standing grant',
'routing':{'lane_id':'openbao-platform-admin-login','verdict':'founder_required','founder_act':'oidc_login','receipt_sha256':'sha256:'+'3'*64},
'owner_reviews':{},'exclusive_window_sha256':'sha256:'+'4'*64,'consumer_trust_sha256':'sha256:'+'5'*64,'original_receipt_sha256':None,'original_execution':None}
c['bindings'].update(proposal_sha256=m.digest((source/m.PLAN).read_bytes()),policy_sha256=m.LIFECYCLE,image_sha256='sha256:'+'1'*64,trust_sha256=c['consumer_trust_sha256'],deployment_sha256=c['deployment_projection_sha256'],executed_revision_sha256=m.digest(m.encoded(c['source_bundle'])))
def approve(value):
if value['action']=='recover' and value['original_execution'] is None:
old=json.loads((directory/(c['operation_id']+'.json')).read_bytes())
value['original_execution']={key:deepcopy(old[key]) for key in ['bindings','writer_sha256','source_ccr_sha256']}
scope=m.review_scope_digest(value)
value['owner_reviews']={role:{'approved_admission_sha256':scope,'approval_ref':'synthetic-fixture-'+role} for role in m.REVIEWS}
return value
approve(c)
return c,io,directory,call,approve,source
def test_actual_native_bootstrap_exact_readback_and_no_retry(native):
c,io,directory,call,approve,source=native
result=m.execute(c,directory,io=io)
assert result['status']=='custody-verified-pending-independent-public-admission' and result['exact_readback']
assert call('GET',m.META)[1]['data']['current_version']==1
assert [(x[1],x[2]) for x in io.calls if x[0]=='http' and x[1]=='POST']==[('POST',m.META),('POST',m.PATH)]
private=call('GET',m.PATH)[1]['data']['data']['ED25519_PRIVATE_KEY']
raw=(directory/(c['operation_id']+'.json')).read_bytes();assert private.encode() not in raw
before=len(io.calls)
with pytest.raises(FileExistsError):m.execute(c,directory,io=io)
assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls[before:])
def test_actual_process_loss_unknown_fresh_recovery_read_only(native):
c,io,directory,call,approve,source=native
child=os.fork()
if child==0:
original_http=io.http
def die_after_native_write(method,path,body=None):
result=original_http(method,path,body)
if method=='POST' and path==m.PATH:os._exit(73)
return result
io.http=die_after_native_write
try:m.execute(c,directory,io=io)
except BaseException:os._exit(74)
os._exit(75)
_,status=os.waitpid(child,0)
assert os.waitstatus_to_exitcode(status)==73
old=directory/(c['operation_id']+'.json');original=old.read_bytes();assert json.loads(original)['status']=='write-intent-unknown'
recovery=deepcopy(c);recovery.update(action='recover',operation_id='synthetic-independent-recovery',original_receipt_sha256=m.digest(original));approve(recovery)
io.lost=False;io.calls.clear()
result=m.execute(recovery,directory,io=io,original_receipt=old)
assert result['status']=='custody-reconciled-pending-independent-public-admission'
assert result['no_write_or_remint'] and old.read_bytes()==original
assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls)
assert call('GET',m.META)[1]['data']['current_version']==1
assert (directory/(recovery['operation_id']+'.json')).stat().st_mode&0o777==0o600
io.calls.clear()
with pytest.raises(FileExistsError):m.execute(recovery,directory,io=io,original_receipt=old)
assert not any(x[0]=='http' for x in io.calls)
@pytest.mark.parametrize('case',['missing-image','missing-trust','mismatched-source','bad-review','bad-route','expired','wrong-entity','wrong-backend','wrong-cluster','root','pod','terminating-pod','hpa','replicas','image-drift','role-drift','pod-after-metadata'])
def test_refusals_no_seed_effect(native,case):
c,io,directory,call,approve,source=native
if case=='missing-image':c['producer_image']=''
elif case=='missing-trust':c['consumer_trust_sha256']=''
elif case=='mismatched-source':(source/'scripts/flex_auth_signer_custody.py').write_text('changed source')
elif case=='bad-review':c['owner_reviews']['founder']['approved_admission_sha256']='sha256:'+'f'*64
elif case=='bad-route':c['routing']['lane_id']='openbao-structure-survey';approve(c)
elif case=='expired':c['expires_at']=(datetime.now(timezone.utc)-timedelta(seconds=1)).isoformat();approve(c)
elif case=='wrong-entity':io.entity='other'
elif case=='wrong-backend':io.backend='other'
elif case=='wrong-cluster':io.cluster='other'
elif case=='root':io.root=True
elif case=='pod':io.pods=[{'spec':{'serviceAccountName':m.NAME}}]
elif case=='terminating-pod':io.pods=[{'metadata':{'deletionTimestamp':'now'},'spec':{'volumes':[{'secret':{'secretName':m.SECRET}}]}}]
elif case=='hpa':io.hpas=[{'spec':{'scaleTargetRef':{'name':m.NAME}}}]
elif case=='replicas':io.dep['spec']['replicas']=1
elif case=='image-drift':io.dep['spec']['template']['spec']['containers'][0]['image']='unreviewed'
elif case=='role-drift':io.role_drift=True
elif case=='pod-after-metadata':io.pod_on_recheck=True
with pytest.raises(Refused):m.execute(c,directory,io=io)
assert not any(x[0]=='http' and x[1]=='POST' and x[2]==m.PATH for x in io.calls)
assert call('GET',m.PATH)[0]==404
@pytest.mark.parametrize('case',['damaged-receipt','typed-damaged-receipt','changed-version','read-denied','no-fresh-review'])
def test_recovery_refuses_without_new_effect(native,case):
c,io,directory,call,approve,source=native;io.lost=True
with pytest.raises(Refused):m.execute(c,directory,io=io)
old=directory/(c['operation_id']+'.json');recovery=deepcopy(c);recovery.update(action='recover',operation_id='recovery',original_receipt_sha256=m.digest(old.read_bytes()));approve(recovery)
if case=='damaged-receipt':old.write_text('{}')
elif case=='typed-damaged-receipt':
damaged=json.loads(old.read_text());damaged['expected_version']=False;old.write_text(json.dumps(damaged));recovery['original_receipt_sha256']=m.digest(old.read_bytes());approve(recovery)
elif case=='changed-version':
doc=call('GET',m.PATH)[1]['data']['data'];assert call('POST',m.PATH,{'options':{'cas':1},'data':doc})[0]==200
elif case=='read-denied':io.denied=True
elif case=='no-fresh-review':recovery['owner_reviews']['founder']['approved_admission_sha256']='sha256:'+'f'*64
io.calls.clear();io.lost=False
with pytest.raises(Refused):m.execute(recovery,directory,io=io,original_receipt=old)
assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls)
@pytest.mark.parametrize('bad_args',[False,True])
def test_main_missing_approval_silent_and_no_io(tmp_path,capsys,bad_args):
if bad_args:
assert m.main(['--unrecognized'])==1
output=capsys.readouterr();assert output.out==output.err==''
return
assert m.main(['--admission',str(tmp_path/'missing'),'--admission-sha256','sha256:'+'0'*64,'--receipt-directory',str(tmp_path)])==1
output=capsys.readouterr();assert output.out==output.err==''
def test_native_command_byte_and_elapsed_bounds_no_output(capsys):
io=m.NativeIO()
with pytest.raises(Refused):io.captured([sys.executable,'-c',"import sys;sys.stdout.write('x'*1048577)"])
import time
started=time.monotonic()
with pytest.raises(Refused):io.captured([sys.executable,'-c',"import time;time.sleep(10)"])
assert time.monotonic()-started<3
output=capsys.readouterr();assert output.out==output.err==''
def test_exclusive_native_window_refuses_second_writer(native):
import fcntl
c,io,directory,call,approve,source=native
fd=os.open(directory/'.signer-window.lock',os.O_RDWR|os.O_CREAT,0o600)
try:
fcntl.flock(fd,fcntl.LOCK_EX|fcntl.LOCK_NB)
with pytest.raises(BlockingIOError):m.execute(c,directory,io=io)
assert io.calls==[]
finally:os.close(fd)
def test_native_fixed_http_transport_against_disposable_backend(bao_dev,monkeypatch,capsys):
origin,token,call,process=bao_dev
assert call('POST','sys/mounts/platform',{'type':'kv','options':{'version':'2'}})[0] in {200,204}
factory=m.http.client.HTTPConnection;port=int(origin.rsplit(':',1)[1]);destinations=[]
def fixture_socket(host,requested_port,*args,**kwargs):
destinations.append((host,requested_port))
return factory(host,port if requested_port==18200 else requested_port,*args,**kwargs)
monkeypatch.setattr(m.http.client,'HTTPConnection',fixture_socket)
io=m.NativeIO();io._token=token
assert io.http('GET',m.META)==(404,{'errors':[]})
assert io.http('POST',m.META,{'cas_required':True,'max_versions':2,'delete_version_after':'0s'})[0] in {200,204}
m.exact_metadata(*io.http('GET',m.META),created=False)
assert all(host=='127.0.0.1' and selected_port==18200 for host,selected_port in destinations)
with pytest.raises(Refused):io.http('GET','other/path')
output=capsys.readouterr();assert output.out==output.err==''
def metadata_phase_crash(native,*,after):
c,io,directory,call,approve,source=native
child=os.fork()
if child==0:
original=io.http
def die(method,path,body=None):
if method=='POST' and path==m.META:
if after:original(method,path,body)
os._exit(73)
return original(method,path,body)
io.http=die
try:m.execute(c,directory,io=io)
except BaseException:os._exit(74)
os._exit(75)
_,status=os.waitpid(child,0);assert os.waitstatus_to_exitcode(status)==73
old=directory/(c['operation_id']+'.json');raw=old.read_bytes();receipt=json.loads(raw)
assert receipt['phase']=='metadata-setup' and receipt['status']=='write-intent-unknown'
assert receipt['public_key'] is None and receipt['kv_version'] is None
recovery=deepcopy(c);recovery.update(action='recover',operation_id='metadata-recovery',original_receipt_sha256=m.digest(raw));approve(recovery)
return old,raw,recovery
@pytest.mark.parametrize('after',[False,True])
def test_real_metadata_process_loss_read_only_phase_recovery(native,after):
c,io,directory,call,approve,source=native
old,raw,recovery=metadata_phase_crash(native,after=after)
io.calls.clear();result=m.execute(recovery,directory,io=io,original_receipt=old)
assert result['status']==('metadata-only-confirmed' if after else 'current-custody-absent')
assert result['public_key'] is result['public_fingerprint'] is result['kv_version'] is None
assert result['key_custody_verified'] is False and result['historical_effect']=='unresolved'
assert 'fresh independently reviewed exact action required' in result['next_action']
assert old.read_bytes()==raw and result['original_unknown_preserved']
assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls)
assert call('GET',m.PATH+'?version=1')==(404,{'errors':[]})
@pytest.mark.parametrize('case',['metadata-denied','metadata-misleading404','metadata-misleading200','metadata-malformed','metadata-timeout','data-denied','unexpected-version'])
def test_metadata_recovery_ambiguous_or_denied_never_classifies_or_writes(native,case):
c,io,directory,call,approve,source=native
old,raw,recovery=metadata_phase_crash(native,after=True)
if case=='unexpected-version':
assert call('POST',m.PATH,{'options':{'cas':0},'data':{'ED25519_PRIVATE_KEY':'synthetic-unadmitted','ED25519_PUBLIC_KEY':'synthetic-unadmitted','kid':c['kid']}})[0]==200
original=io.http
def faulty(method,path,body=None):
if path==m.META:
if case=='metadata-denied':return 403,{'errors':['denied']}
if case=='metadata-misleading404':return 404,{'errors':['permission denied']}
if case=='metadata-misleading200':
result=original(method,path,body);result[1]['errors']=['denied'];return result
if case=='metadata-malformed':return 200,{'data':{'current_version':False}}
if case=='metadata-timeout':raise OSError('synthetic private backend detail')
if path==m.PATH+'?version=1' and case=='data-denied':return 404,{'errors':['denied']}
return original(method,path,body)
io.http=faulty;io.calls.clear()
with pytest.raises((Refused,OSError)):m.execute(recovery,directory,io=io,original_receipt=old)
evidence=json.loads((directory/(recovery['operation_id']+'.json')).read_bytes())
assert evidence['status']=='recovery-read-intent-unconfirmed' and evidence['key_custody_verified'] is False
assert old.read_bytes()==raw
assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls)
if case=='unexpected-version':assert not any(x[0]=='http' and x[2]==m.PATH+'?version=1' for x in io.calls)
def test_stale_current_primitive_lineage_refuses_before_native_io(native):
c,io,directory,call,approve,source=native
plan=json.loads((source/m.PLAN).read_bytes());plan['bootstrap']['source_primitive_sha256']='sha256:'+'8'*64
(source/m.PLAN).write_text(json.dumps(plan));c['bindings']['proposal_sha256']=m.digest((source/m.PLAN).read_bytes());approve(c)
with pytest.raises(Refused,match='primitive lineage'):m.execute(c,directory,io=io)
assert io.calls==[]
def test_recovery_explicitly_binds_historical_execution_and_current_source(native):
c,io,directory,call,approve,source=native
old,raw,recovery=metadata_phase_crash(native,after=True)
# Model a separately retained older executed bundle/proposal. It must be
# explicitly selected in fresh recovery review, never treated as current.
original=json.loads(raw);original['bindings']['executed_revision_sha256']='sha256:'+'6'*64
original['bindings']['proposal_sha256']='sha256:'+'7'*64
old.write_text(json.dumps(original));recovery['original_receipt_sha256']=m.digest(old.read_bytes())
recovery['original_execution']={key:deepcopy(original[key]) for key in ['bindings','writer_sha256','source_ccr_sha256']};approve(recovery)
result=m.execute(recovery,directory,io=io,original_receipt=old)
assert result['status']=='metadata-only-confirmed'
assert result['original_execution']['bindings']['executed_revision_sha256']!=recovery['bindings']['executed_revision_sha256']
assert json.loads(old.read_text())==original
def test_generated_but_unstored_seed_phase_recovers_without_public_admission(native):
c,io,directory,call,approve,source=native
io.pod_on_recheck=True
with pytest.raises(Refused):m.execute(c,directory,io=io)
old=directory/(c['operation_id']+'.json');raw=old.read_bytes();receipt=json.loads(raw)
assert receipt['phase']=='seed-cas' and receipt['public_key'] is not None
assert call('GET',m.PATH+'?version=1')==(404,{'errors':[]})
io.pod_on_recheck=False;io.pods=[];io.calls.clear()
recovery=deepcopy(c);recovery.update(action='recover',operation_id='unstored-seed-recovery',original_receipt_sha256=m.digest(raw));approve(recovery)
result=m.execute(recovery,directory,io=io,original_receipt=old)
assert result['status']=='metadata-only-confirmed' and result['key_custody_verified'] is False
assert result['public_key'] is None and result['public_fingerprint'] is None
assert old.read_bytes()==raw
assert not any(x[0]=='http' and x[1]=='POST' for x in io.calls)
def test_exact_runtime_storage_owner_slot_replaces_conflated_role(native):
c,io,directory,call,approve,source=native
assert m.REVIEWS=={'founder','railiance-platform-owner','access-engine-owner','secrets-engine-owner','cluster-runtime-storage-owner'}
assert m.validate_admission(c)>5
old=deepcopy(c)
old['owner_reviews']['cluster-gitops-owner']=old['owner_reviews'].pop('cluster-runtime-storage-owner')
with pytest.raises(Refused,match='distinct owner reviews'):
m.validate_admission(old)
missing=deepcopy(c);missing['owner_reviews'].pop('cluster-runtime-storage-owner')
with pytest.raises(Refused,match='distinct owner reviews'):
m.validate_admission(missing)
extra=deepcopy(c);extra['owner_reviews']['railiance-enablement-owner']=next(iter(extra['owner_reviews'].values()))
with pytest.raises(Refused,match='distinct owner reviews'):
m.validate_admission(extra)
assert io.calls==[]
def test_owner_reviews_survive_fresh_expiry_but_not_scope_change(native):
c,io,directory,call,approve,source=native
reviewed=m.review_scope_digest(c)
c['expires_at']=(datetime.now(timezone.utc)+timedelta(seconds=90)).isoformat()
assert m.review_scope_digest(c)==reviewed
m.validate_admission(c)
changed=deepcopy(c);changed['kid']='other-native-kid'
assert m.review_scope_digest(changed)!=reviewed
with pytest.raises(m.Refused):m.validate_admission(changed)