Assistant: codex Assistant-Model: gpt-6.1-sol Assistant-Session: 01a126e1-76f8-7643-8cf3-e93336539ade
198 lines
13 KiB
Python
198 lines
13 KiB
Python
"""Offline route readiness: public responses and lifecycle mocks only."""
|
|
import importlib.util
|
|
import json
|
|
from pathlib import Path
|
|
import unittest
|
|
from unittest.mock import patch
|
|
import copy
|
|
import time
|
|
import tempfile
|
|
import sys
|
|
import signal
|
|
import io
|
|
|
|
spec=importlib.util.spec_from_file_location('fixtures',Path(__file__).with_name('test_openbao_negative_session.py'))
|
|
f=importlib.util.module_from_spec(spec);spec.loader.exec_module(f);s=f.s
|
|
HEALTH={'initialized':True,'sealed':False,'standby':False,'performance_standby':False,'cluster_id':'synthetic-public-cluster'}
|
|
PIN=s.digest(HEALTH['cluster_id'].encode())
|
|
|
|
class NodeRouteTests(unittest.TestCase):
|
|
def setUp(self):
|
|
s.CLEANING=False;s.REQUEST_DEADLINE=None
|
|
s.BUSINESS_MONOTONIC_DEADLINE=None;s.CLEANUP_MONOTONIC_DEADLINE=None
|
|
|
|
def test_public_health_get_has_no_authentication_and_only_digest_retained(self):
|
|
transport=s.SessionTransport('http://127.0.0.1:18200');receipt={}
|
|
response=type('Response',(),{'getcode':lambda self:200,'read':lambda self,size:json.dumps(HEALTH).encode(),'close':lambda self:None})()
|
|
with patch.object(transport.opener,'open',return_value=response) as calls:
|
|
s.verify_bao_route(transport,{'bao_health_identity_sha256':PIN},receipt)
|
|
req=calls.call_args.args[0]
|
|
self.assertEqual(req.full_url,'http://127.0.0.1:18200/v1/sys/health')
|
|
self.assertEqual(req.method,'GET');self.assertEqual(req.headers,{})
|
|
self.assertEqual(receipt,{'bao_public_route_verified':True})
|
|
self.assertNotIn(HEALTH['cluster_id'],json.dumps(receipt))
|
|
|
|
def test_unreachable_redirect_sealed_standby_uninitialized_and_malformed_health_refuse(self):
|
|
transport=s.SessionTransport('http://openbao.openbao.svc:8200')
|
|
cases=[(None,b''),(302,b'{}'),(503,json.dumps(HEALTH).encode()),(200,b'not-json'),
|
|
(200,b'[]'),(200,json.dumps(dict(HEALTH,sealed=True)).encode()),
|
|
(200,json.dumps(dict(HEALTH,initialized=False)).encode()),
|
|
(200,json.dumps(dict(HEALTH,standby=True)).encode()),
|
|
(200,json.dumps(dict(HEALTH,sealed=0)).encode()),
|
|
(200,json.dumps(dict(HEALTH,cluster_id='')).encode())]
|
|
for status,body in cases:
|
|
with self.subTest(status=status,body_length=len(body)),patch.object(transport,'request',return_value=(status,body)):
|
|
with self.assertRaises(s.Refused):transport.health_identity()
|
|
|
|
def test_identity_drift_or_missing_approved_pin_refuse(self):
|
|
transport=s.SessionTransport('http://127.0.0.1:18200')
|
|
with patch.object(transport,'health_identity',return_value=PIN) as health:
|
|
with self.assertRaisesRegex(s.Refused,'bao_public_health_identity_changed'):
|
|
s.verify_bao_route(transport,{'bao_health_identity_sha256':'0'*64},{})
|
|
health.reset_mock()
|
|
with self.assertRaisesRegex(s.Refused,'approved_bao_health_identity_required'):
|
|
s.verify_bao_route(transport,{}, {})
|
|
health.assert_not_called()
|
|
|
|
def setup_execute(self):
|
|
raw=f.baseline()
|
|
spec={'replicas':1,'strategy':{'type':'Recreate'},'template':{'spec':{'containers':[{'name':'keycape','env':[]}]}}}
|
|
config={'metadata':{'name':'keycape-config','uid':'cfg','resourceVersion':'1'},'data':{'config.yaml':s.base64.b64encode(raw.encode()).decode()}}
|
|
dep={'metadata':{'name':'keycape','uid':'dep','resourceVersion':'1'},'spec':spec}
|
|
e=f.envelope();e.update(runner_path='fixture-runner',bao_health_identity_sha256=PIN,
|
|
config_metadata=s.meta(config),deployment_metadata=s.meta(dep),registry_sha256=s.digest(raw.encode()),deployment_spec_sha256=s.canonical(spec))
|
|
e['source_hashes']['fixture-runner']='fixture'
|
|
return e,config,dep
|
|
|
|
def test_unavailable_initial_node_route_stops_before_any_native_or_secret_access(self):
|
|
e,config,dep=self.setup_execute()
|
|
with patch.object(s,'verify_sources',return_value=150),patch.object(s,'load_probe'), \
|
|
patch.object(s,'SessionTransport') as factory,patch.object(s,'k') as k,patch.object(s,'get') as get:
|
|
factory.return_value.discovery.return_value={'issuer':'https://kc.coulomb.social','token_endpoint':'https://kc.coulomb.social/token'}
|
|
factory.return_value.health_identity.side_effect=s.Refused('bao_public_health_unavailable')
|
|
with self.assertRaisesRegex(s.Refused,'bao_public_health_unavailable'):
|
|
s.execute(e,{'human_token':'synthetic','coding_agent_token':'synthetic'}, {})
|
|
k.assert_not_called();get.assert_not_called()
|
|
|
|
def test_route_loss_after_dry_runs_stops_before_temporary_create_or_restarts(self):
|
|
e,config,dep=self.setup_execute()
|
|
with patch.object(s,'verify_sources',return_value=150),patch.object(s,'load_probe'), \
|
|
patch.object(s,'SessionTransport') as factory, \
|
|
patch.object(s,'k',return_value={'metadata':{'uid':s.CLUSTER}}) as k, \
|
|
patch.object(s,'get',side_effect=[config,dep]),patch.object(s,'patch') as patches,patch.object(s,'ready',return_value=True):
|
|
factory.return_value.discovery.return_value={'issuer':'https://kc.coulomb.social','token_endpoint':'https://kc.coulomb.social/token'}
|
|
factory.return_value.health_identity.side_effect=[PIN,s.Refused('bao_public_health_unavailable')]
|
|
with self.assertRaisesRegex(s.Refused,'bao_public_health_unavailable'):
|
|
s.execute(e,{'human_token':'synthetic','coding_agent_token':'synthetic'}, {})
|
|
self.assertEqual(factory.return_value.health_identity.call_count,2)
|
|
self.assertTrue(all(c.kwargs.get('dry') is True for c in patches.call_args_list))
|
|
self.assertTrue(all(c.args[0][0]!='create' or '--dry-run=server' in c.args[0] for c in k.call_args_list))
|
|
|
|
def test_recovery_route_refusal_precedes_native_reads(self):
|
|
e,config,dep=self.setup_execute();e['disposition']='recovery-approved'
|
|
with patch.object(s,'verify_sources',return_value=None),patch.object(s,'SessionTransport') as factory, \
|
|
patch.object(s,'k') as k,patch.object(s,'get') as get:
|
|
factory.return_value.health_identity.side_effect=s.Refused('bao_public_health_unavailable')
|
|
with self.assertRaisesRegex(s.Refused,'bao_public_health_unavailable'):
|
|
s.recover(e,{})
|
|
k.assert_not_called();get.assert_not_called()
|
|
|
|
def test_public_health_uses_total_elapsed_limit(self):
|
|
transport=s.SessionTransport('http://127.0.0.1:18200')
|
|
class Slow:
|
|
def getcode(self):return 200
|
|
def read(self,size):time.sleep(0.5);return json.dumps(HEALTH).encode()
|
|
def close(self):pass
|
|
started=time.monotonic()
|
|
with patch.object(s,'HTTP_TOTAL_SECONDS',0.008),patch.object(transport.opener,'open',return_value=Slow()):
|
|
with self.assertRaisesRegex(s.Refused,'request_total_timeout'):transport.health_identity()
|
|
self.assertLess(time.monotonic()-started,0.08)
|
|
|
|
def test_public_route_mode_has_no_native_secret_or_private_input(self):
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
receipt=Path(folder)/'receipt.json'
|
|
argv=['session','route-preflight','--bao-addr','http://127.0.0.1:18200','--receipt',str(receipt)]
|
|
with patch.object(sys,'argv',argv),patch.object(s,'SessionTransport') as factory, \
|
|
patch.object(s,'k') as k,patch.object(s,'get') as get,patch.object(sys,'stdin') as stdin:
|
|
factory.return_value.health_identity.return_value=PIN
|
|
self.assertEqual(s.main(),0)
|
|
k.assert_not_called();get.assert_not_called();stdin.read.assert_not_called()
|
|
data=json.loads(receipt.read_text())
|
|
self.assertEqual(data['bao_health_identity_sha256'],PIN)
|
|
self.assertEqual(data['probe_location'],'current_process_only')
|
|
self.assertFalse(data['native_accepted'])
|
|
|
|
def main_fixture(self,folder,mode):
|
|
envelope=f.envelope()
|
|
envelope['bao_health_identity_sha256']=PIN
|
|
if mode=='recover':envelope['disposition']='recovery-approved'
|
|
path=Path(folder)/'approved.json';path.write_text(json.dumps(envelope));path.chmod(0o600)
|
|
receipt=Path(folder)/'receipt.json'
|
|
argv=['session',mode,'--envelope',str(path),'--receipt',str(receipt)]
|
|
return envelope,receipt,argv
|
|
|
|
def test_actual_main_health_failure_never_reads_private_stdin_execute_or_recover(self):
|
|
previous=signal.getsignal(signal.SIGTERM)
|
|
try:
|
|
for mode in ['execute','recover']:
|
|
with self.subTest(mode=mode),tempfile.TemporaryDirectory() as folder:
|
|
e,receipt,argv=self.main_fixture(folder,mode)
|
|
with patch.object(sys,'argv',argv),patch.object(s,'SessionTransport') as factory, \
|
|
patch.object(sys,'stdin') as stdin,patch.object(s,'k') as k,patch.object(s,'get') as get:
|
|
factory.return_value.health_identity.side_effect=s.Refused('bao_public_health_unavailable')
|
|
self.assertEqual(s.main(),1)
|
|
stdin.read.assert_not_called();stdin.buffer.read.assert_not_called();k.assert_not_called();get.assert_not_called()
|
|
data=json.loads(receipt.read_text())
|
|
self.assertEqual(data['reason'],'bao_public_health_unavailable')
|
|
self.assertFalse(data['cleanup_verified'])
|
|
s.CLEANING=False;s.CLEANUP_MONOTONIC_DEADLINE=None
|
|
finally:signal.signal(signal.SIGTERM,previous)
|
|
|
|
def test_actual_main_missing_approved_health_pin_never_reads_stdin(self):
|
|
previous=signal.getsignal(signal.SIGTERM)
|
|
try:
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
e,receipt,argv=self.main_fixture(folder,'execute')
|
|
del e['bao_health_identity_sha256']
|
|
Path(argv[3]).write_text(json.dumps(e))
|
|
with patch.object(sys,'argv',argv),patch.object(sys,'stdin') as stdin, \
|
|
patch.object(s,'SessionTransport') as factory,patch.object(s,'k') as k:
|
|
self.assertEqual(s.main(),1)
|
|
stdin.read.assert_not_called();stdin.buffer.read.assert_not_called();factory.return_value.health_identity.assert_not_called();k.assert_not_called()
|
|
self.assertEqual(json.loads(receipt.read_text())['reason'],'approved_bao_health_identity_required')
|
|
finally:signal.signal(signal.SIGTERM,previous)
|
|
|
|
def test_actual_main_health_succeeds_before_stdin_and_preserves_started_window(self):
|
|
previous=signal.getsignal(signal.SIGTERM);events=[];started={}
|
|
try:
|
|
with tempfile.TemporaryDirectory() as folder:
|
|
e,receipt,argv=self.main_fixture(folder,'execute')
|
|
def health():
|
|
events.append('health');started['deadline']=s.BUSINESS_MONOTONIC_DEADLINE;return PIN
|
|
payloads=iter([b'{"human_token":"synthetic","coding_agent_token":"synthetic"}',b''])
|
|
def private_read(size):
|
|
if 'stdin' not in events:events.append('stdin')
|
|
self.assertGreater(size,0);return next(payloads)
|
|
def execute(*args,**kwargs):
|
|
events.append('execute');self.assertTrue(kwargs['window_started'])
|
|
self.assertEqual(s.BUSINESS_MONOTONIC_DEADLINE,started['deadline'])
|
|
with patch.object(sys,'argv',argv),patch.object(s,'SessionTransport') as factory, \
|
|
patch.object(sys,'stdin') as stdin,patch.object(s,'emit_private_ready'),patch.object(s,'execute',side_effect=execute), \
|
|
patch.object(s,'k') as k:
|
|
factory.return_value.health_identity.side_effect=health
|
|
stdin.buffer.read.side_effect=private_read
|
|
self.assertEqual(s.main(),0);k.assert_not_called()
|
|
self.assertEqual(events,['health','stdin','execute'])
|
|
finally:signal.signal(signal.SIGTERM,previous)
|
|
|
|
def test_execute_does_not_renew_expired_preinput_monotonic_window(self):
|
|
e=f.envelope();s.start_execution_window(e)
|
|
original=s.BUSINESS_MONOTONIC_DEADLINE
|
|
with patch.object(s.time,'monotonic',return_value=original+0.01),patch.object(s,'load_probe') as load, \
|
|
patch.object(s,'k') as k:
|
|
with self.assertRaisesRegex(s.Refused,'session_business_budget_expired'):
|
|
s.execute(e,{'human_token':'synthetic','coding_agent_token':'synthetic'}, {},window_started=True)
|
|
load.assert_not_called();k.assert_not_called()
|
|
self.assertEqual(s.BUSINESS_MONOTONIC_DEADLINE,original)
|
|
|
|
if __name__=='__main__':unittest.main(verbosity=2)
|