diff --git a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/helper/seed_policy.py b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/helper/seed_policy.py index ae9c933..20d5f50 100644 --- a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/helper/seed_policy.py +++ b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/helper/seed_policy.py @@ -1,25 +1,109 @@ """Literal owned direct-apphost transport; inherited canonical infolog semantics. Inert without the selected startup runner's concrete live custody context. """ -import os,time,json,hashlib,selectors,signal,subprocess,pathlib +import os,time,json,hashlib,selectors,signal,subprocess,pathlib,re from growing_log import GrowingLog,_unique,_policy_observation,POLICY_TO_MECHANICAL,MAX_POLICY_INPUT from private_io import need,Refused from runtime_identity import mark_failure +def policy_argv(policy,invocation): + need(re.fullmatch('[0-9a-f]{64}',invocation or ''),'exact policy invocation') + need(policy['environment']=={'PATH':'/usr/bin:/bin'},'literal policy environment') + return [policy['apphost'],'--closure-manifest',policy['closurePath'],'--closure-sha256',policy['closureSha256'],'--invocation-id',invocation] + +def _entry(context): + if type(context)is SeedPolicyContext: + import startup_runner as entry + elif type(context)is PolicyOnlyContext: + import policy_transport_runner as entry + else:raise Refused('closed concrete policy context') + return entry + +def _validate(context): + import mechanics as m + need(type(context.owner)is m.LinuxOwner,'concrete held Linux policy owner') + entry=_entry(context);a=m.load(context.admission) + entry.source_binding(a,context.profile) + need(a['operation']==('seed-attribution-startup-only'if type(context)is SeedPolicyContext else 'policy-transport-qualification-only'),'matching admitted policy composition') + need(context.profile==entry.profile(),'actual pinned concrete policy profile') + need(context.evidence_root==pathlib.Path(entry.ROOT)/'evidence','literal bound evidence root') + need(context.profile['policy']['environment']=={'PATH':'/usr/bin:/bin'},'literal bound policy environment') + return entry,a + +def launch_policy(context,invocation,deadline): + import mechanics as m + need(context.active is None and context.evaluations<3 and len(context.reaped)==context.evaluations,'one settled policy child before next evaluation') + entry,a=_validate(context) + command=policy_argv(context.profile['policy'],invocation) + need(context.pump(deadline)==(1 if type(context)is SeedPolicyContext else 0),'exact prelaunch task CLR count') + if type(context)is SeedPolicyContext:entry.runtime_socket().directory_check() + context.evaluations+=1;name='policy-'+str(context.evaluations) + end=min(deadline,context.deadline-8);rd,rw=os.pipe();ar,aw=os.pipe();child=None + try: + argv=[entry.PYTHON,'-I','-B',str(entry.HERE/entry.__file__.split('/')[-1]),'--shim','policy','--admission',str(context.admission),'--ready',str(rw),'--ack',str(ar),'--invocation',invocation] + child=subprocess.Popen(argv,env=context.profile['policy']['environment'],pass_fds=(rw,ar),start_new_session=True,stdin=subprocess.PIPE,stdout=subprocess.PIPE,stderr=subprocess.PIPE,umask=0o077) + context.active=child;context.children[name]=child;context.owner.leaders.add(child.pid) + os.close(rw);rw=-1;os.close(ar);ar=-1 + with selectors.DefaultSelector()as sel: + sel.register(rd,selectors.EVENT_READ) + while True: + context.pump(end) + if sel.select(m.remaining(end,.02)):break + need(os.read(rd,64)==b'BAR-POLICY-READY\n','policy preexec handshake') + ident=m.identity(child.pid) + need(ident['pgid']==ident['session']==child.pid and ident['ppid']==os.getpid()and ident['uid']==os.geteuid(),'actual owned policy identity') + if child.pid not in context.owner.records:context.owner.acquire(ident) + need(m.same(ident,context.owner.records[child.pid])and child.pid in context.owner.handles,'held policy pidfd before GO') + need(os.sched_getaffinity(child.pid)=={a['cpu']},'policy serial affinity') + m.write_new(context.evidence_root/(name+'.process.json'),dict(identity=ident,argv=command,environment=context.profile['policy']['environment'],heldPidfdBeforeGO=True,sourceSHA256=a['sourceSHA256'],profileSHA256=a['profileSHA256'])) + os.write(aw,b'GO\n');return child + except BaseException: + # Ownership is retained in the context even when the handshake failed. + # Caller/outer cleanup records the first failure and held settlement. + if child is not None and child.pid not in context.owner.records: + context.owner.observe() + raise + finally: + for fd in [rd,rw,ar,aw]: + if fd>=0: + try:os.close(fd) + except OSError:pass + +def policy_shim(args,entry,p,a): + import mechanics as m + import sys + kind='startup_runner'if entry is sys.modules.get('startup_runner')else 'policy_transport_runner'if entry is sys.modules.get('policy_transport_runner')else None + need(kind is not None,'literal policy shim caller') + entry.source_binding(a,p) + need(args.shim=='policy'and os.sched_getaffinity(0)=={a['cpu']},'literal policy shim and affinity') + parent=m.load(pathlib.Path(entry.ROOT)/'evidence/worker-start.json') + need(m.same(parent['worker'],m.identity(os.getppid()))and parent['admissionSHA256']==m.digest(args.admission),'source-bound actual policy parent') + if kind=='startup_runner':entry.runtime_socket().directory_check() + argv=policy_argv(p['policy'],args.invocation) + os.write(args.ready,b'BAR-POLICY-READY\n');os.close(args.ready) + need(os.read(args.ack,16)==b'GO\n','actual held policy release');os.close(args.ack) + entry.source_binding(a,p) + if kind=='startup_runner':entry.runtime_socket().directory_check() + os.chdir(entry.ROOT);os.execve(argv[0],argv,p['policy']['environment']) + +def settle_policy(context,child,deadline,force=False): + import mechanics as m + need(child is context.active,'exact policy child settlement') + if child.pid not in context.owner.records:context.owner.observe() + ident=context.owner.records[child.pid] + if force and child.poll()is None:context.owner.send(ident,signal.SIGKILL) + end=min(context.deadline,time.monotonic()+3)if force else deadline + remaining=end-time.monotonic();need(remaining>0,'policy settlement Unknown: deadline') + code=child.wait(timeout=remaining);context.owner.leaders.discard(child.pid) + context.reaped.append({'identity':ident,'exitCode':code,'reaped':True,'forced':force});context.active=None;return code + class SeedPolicyContext: def __init__(self,profile,admission,owner,children,actor_selector,streams,counts,deadline): - self.profile=profile;self.admission=admission;self.owner=owner;self.children=children;self.actor_selector=actor_selector;self.streams=streams;self.counts=counts;self.deadline=deadline;self.evaluations=0;self.active=None;self.reaped=[] + import startup_runner as runner + self.profile=profile;self.admission=admission;self.owner=owner;self.children=children;self.actor_selector=actor_selector;self.streams=streams;self.counts=counts;self.deadline=deadline;self.evaluations=0;self.active=None;self.reaped=[];self.evidence_root=pathlib.Path(runner.ROOT)/'evidence' def pump(self,deadline): - # This is the real actor selector/owner/quota, not an injected success callback. import startup_runner as runner need(time.monotonic()0,'policy settlement Unknown: deadline') - code=child.wait(timeout=remaining);self.owner.leaders.discard(child.pid);self.reaped.append({'identity':ident,'exitCode':code,'reaped':True});self.active=None;return code + need(time.monotonic()=0: + try:os.close(fd) + except OSError:pass + if owned: + try:result['independentCustody']=owned.settle(deadline);need(result['independentCustody']['leaderReaped']and not result['independentCustody']['remaining']and not result['independentCustody']['errors'],'independent complete settlement') + except BaseException as error:fail('outer-cleanup',error) + else:fail('outer-cleanup',m.CleanupUnknown('independent owner unavailable')) + try: + result['postOriginals']=originals(p,deadline);inner=m.load(A/'evidence/transport-result.json');result['inner']=inner + need(inner['transportQualified']and inner['innerCleanup']['status']=='settled'and result.get('workerExitCode')==0,'inner transport and cleanup required') + except BaseException as error:fail('inner/pins',error) + for name,raw in buffers.items(): + try:bytes_new(A/'logs'/('outer-'+name+'.raw'),bytes(raw),524288) + except BaseException as error:fail('raw-publication',error) + try:json_new(A/'evidence/full-output-census.json',{'files':m.census(A),'scope':'before final outer receipt; root final census required'});result['finalQuota']=quota() + except BaseException as error:fail('final-census',error) + result.update(transportQualified=failure is None and not result['secondaryFailures'],failure=str(failure)if failure else None,elapsedSeconds=time.monotonic()-started,operationCount=1,noRetry=True,nativeSeedQualified=False,actorEligible=False,nativeUsefulPlay='0/6',noGameBrowserArmOrCommands=True,sourceLinkRemoteContent='Unknown',rootVerdict='Pending root full review') + encoded=(json.dumps(result,sort_keys=True,separators=(',',':'))+'\n').encode();q=result.get('finalQuota',{}) + if 'files'not in q or q['files']+1>1024 or q['bytes']+len(encoded)>134217728:result.update(transportQualified=False,failure=result.get('failure')or'final receipt quota reserve') + json_new(A/'evidence/outer-result.json',result,1048576) + return 0 if result['transportQualified']else 3 + +def main(): + parser=argparse.ArgumentParser();parser.add_argument('--admission',required=True);parser.add_argument('--worker',action='store_true');parser.add_argument('--shim',choices=['policy']);parser.add_argument('--ready',type=int);parser.add_argument('--ack',type=int);parser.add_argument('--invocation');args=parser.parse_args() + need(not(args.worker and args.shim),'one closed entry') + if args.shim:return shim(args) + if args.worker:return worker(args) + need(args.ready is None and args.ack is None and args.invocation is None,'no outer command/payload selection');return execute(pathlib.Path(args.admission)) +if __name__=='__main__': + sys.modules['policy_transport_runner']=sys.modules[__name__] + raise SystemExit(main()) diff --git a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/run-source-controls.py b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/run-source-controls.py index 55185b3..1a32265 100644 --- a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/run-source-controls.py +++ b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/run-source-controls.py @@ -13,11 +13,11 @@ def forbidden(*args,**kwargs):raise RuntimeError('portable source controls prohi os.system=forbidden for name in ['fork','forkpty','posix_spawn','posix_spawnp','execv','execve','execvp','execvpe']: if hasattr(os,name):setattr(os,name,forbidden) -FILES=('test_qualify_prearm.py','test_native_evidence.py','helper/test_prearm_startup.py','helper/test_seed_policy.py','helper/test_capture_custody.py','helper/test_loaded_custody.py','helper/test_settings_custody.py','helper/test_proc_bytes.py','fixture/tests/test_prearm_observation.py') +FILES=('test_policy_transport_runner.py','test_qualify_prearm.py','test_native_evidence.py','helper/test_prearm_startup.py','helper/test_seed_policy.py','helper/test_capture_custody.py','helper/test_loaded_custody.py','helper/test_settings_custody.py','helper/test_proc_bytes.py','fixture/tests/test_prearm_observation.py') suite=unittest.TestSuite() for index,name in enumerate(FILES): spec=importlib.util.spec_from_file_location('portable_seed_controls_'+str(index),ROOT/name);module=importlib.util.module_from_spec(spec);spec.loader.exec_module(module);suite.addTests(unittest.defaultTestLoader.loadTestsFromModule(module)) -expected=71 +expected=89 if suite.countTestCases()!=expected:raise SystemExit('portable source control roster changed: '+str(suite.countTestCases())) result=unittest.TextTestRunner(verbosity=2).run(suite) if not result.wasSuccessful()or result.testsRun!=expected or result.skipped:raise SystemExit(1) diff --git a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/startup_runner.py b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/startup_runner.py index 83c907f..47e86ba 100644 --- a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/startup_runner.py +++ b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/startup_runner.py @@ -25,7 +25,7 @@ def profile(): validate_schema(p) need(p['requiredHostMappings']==required and len(required)==3,'literal pinned apphost/coreclr/clrjit') need(p['policy']['environment']=={'PATH':'/usr/bin:/bin'} and p['policy']['maximumSimultaneousChildren']==1 and p['policy']['maximumEvaluations']==3 and p['policy']['deadlineSeconds']==5 and p['policy']['inputBytes']==16777216 and p['policy']['outputBytes']==131072,'literal closed policy caps') - need(set(p['sourceHelperPins'])=={'helper/runtime_identity.py','helper/stock_bootstrap.py','helper/dynamic_mapping.py','helper/snapshot_publication.py','helper/mapping_profile.py','helper/seed_policy.py','helper/growing_log.py','helper/loaded_custody.py','helper/settings_custody.py','qualify_prearm.py','native_evidence.py'},'closed successor source helpers') + need(set(p['sourceHelperPins'])=={'helper/runtime_identity.py','helper/stock_bootstrap.py','helper/dynamic_mapping.py','helper/snapshot_publication.py','helper/mapping_profile.py','helper/seed_policy.py','helper/growing_log.py','helper/loaded_custody.py','helper/settings_custody.py','qualify_prearm.py','native_evidence.py','policy_transport_runner.py'},'closed successor source helpers') for path,sha in p['sourceHelperPins'].items():need(m.digest(HERE/path)==sha,'exact profile helper byte pin') return p @@ -71,7 +71,8 @@ def commands(p,invocation=None): ports=p['proposedPorts'];A=pathlib.Path(ROOT) result={'host':[p['nativeHost'],'--stock-tactical-live-host',f"127.0.0.1:{ports['grpc']}",f"http://127.0.0.1:{ports['gateway']}",f"http://127.0.0.1:{ports['unusedReceiverOrigin']}",str(A/'host'),p['source']['fsbarCommit']], 'engine':[p['engine'],'--isolation','--isolation-dir',p['dataRoot'],'--write-dir',str(A/'engine'),'--config',str(A/'engine/springsettings.cfg'),p['startscript']]} if invocation is not None: - need(re.fullmatch('[0-9a-f]{64}',invocation),'exact policy invocation');result['policy']=[p['policy']['apphost'],'--closure-manifest',p['policy']['closurePath'],'--closure-sha256',p['policy']['closureSha256'],'--invocation-id',invocation] + from seed_policy import policy_argv + result['policy']=policy_argv(p['policy'],invocation) return result def runtime_socket(): @@ -140,25 +141,25 @@ def record_tail(path,label): def launch(role,p,a_path,owner,deadline,registered,invocation=None,evaluation=None,cleanup_reserve=8,policy_context=None): need(role in ['host','engine','policy'],'literal launch role') - need((role!='policy' and invocation is None and evaluation is None) or (role=='policy' and re.fullmatch('[0-9a-f]{64}',invocation or '') and evaluation in [1,2,3]),'literal invocation/evaluation') - name=role if role!='policy'else 'policy-'+str(evaluation) + if role=='policy': + from seed_policy import SeedPolicyContext,launch_policy + need(type(policy_context)is SeedPolicyContext and policy_context.owner is owner and policy_context.children is registered and policy_context.profile is p and str(policy_context.admission)==str(a_path),'exact native policy caller') + return launch_policy(policy_context,invocation,deadline) + need(role in ['host','engine']and invocation is None and evaluation is None,'literal native actor launch') + name=role end=min(deadline-cleanup_reserve,clock()+5);rd,rw=os.pipe();ar,aw=os.pipe();child=None try: runtime_socket().directory_check() shim_argv=[PYTHON,'-I','-B',str(HERE/'startup_runner.py'),'--shim',role,'--admission',str(a_path),'--ready',str(rw),'--ack',str(ar)] - if role=='policy':shim_argv+=['--invocation',invocation] - child=subprocess.Popen(shim_argv,env=environment(p,role),pass_fds=(rw,ar),start_new_session=True,stdin=subprocess.PIPE if role=='policy'else None,stdout=subprocess.PIPE,stderr=subprocess.PIPE,umask=0o077) + child=subprocess.Popen(shim_argv,env=environment(p,role),pass_fds=(rw,ar),start_new_session=True,stdin=None,stdout=subprocess.PIPE,stderr=subprocess.PIPE,umask=0o077) registered[name]=child;owner.leaders.add(child.pid);os.close(rw);rw=-1;os.close(ar);ar=-1 with selectors.DefaultSelector()as sel: sel.register(rd,selectors.EVENT_READ) while True: - if role=='policy': - from seed_policy import SeedPolicyContext - need(type(policy_context)is SeedPolicyContext,'concrete policy preexec supervision context');policy_context.pump(end) - if sel.select(m.remaining(end,.02 if role=='policy'else 5)):break + if sel.select(m.remaining(end,5)):break need(os.read(rd,64)==b'BAR-STARTUP-READY\n','actor preexec handshake') ident=m.identity(child.pid);need(ident['pgid']==ident['session']==child.pid and ident['ppid']==os.getpid(),'actual owned actor identity');owner.acquire(ident);need(os.sched_getaffinity(child.pid)=={m.load(a_path)['cpu']},'actor serial affinity') - m.write_new(pathlib.Path(ROOT)/'evidence'/(name+'.process.json'),dict(identity=ident,argv=commands(p,invocation)[role],environment=environment(p,role)));os.write(aw,b'GO\n');return child + m.write_new(pathlib.Path(ROOT)/'evidence'/(name+'.process.json'),dict(identity=ident,argv=commands(p)[role],environment=environment(p,role)));os.write(aw,b'GO\n');return child finally: for fd in [rd,rw,ar,aw]: if fd>=0: @@ -312,7 +313,11 @@ def source_binding(a,p): need(a['sourceSHA256']==reviewed_source()and a['profileSHA256']==m.digest(HERE/'startup-profile.json'),'shim/worker exact source') def shim(args): - p=profile();a=m.load(args.admission);source_binding(a,p);need(args.shim in ['host','engine','policy'],'literal roles');need((args.shim=='policy' and re.fullmatch('[0-9a-f]{64}',args.invocation or ''))or(args.shim!='policy' and args.invocation is None),'shim literal invocation');need(os.sched_getaffinity(0)=={a['cpu']},'shim affinity') + p=profile();a=m.load(args.admission);source_binding(a,p) + if args.shim=='policy': + from seed_policy import policy_shim + return policy_shim(args,sys.modules[__name__],p,a) + need(args.shim in ['host','engine','policy'],'literal roles');need((args.shim=='policy' and re.fullmatch('[0-9a-f]{64}',args.invocation or ''))or(args.shim!='policy' and args.invocation is None),'shim literal invocation');need(os.sched_getaffinity(0)=={a['cpu']},'shim affinity') parent=m.load(pathlib.Path(ROOT)/'evidence/worker-start.json');need(m.same(parent['worker'],m.identity(os.getppid()))and parent['admissionSHA256']==m.digest(args.admission),'owned source-bound parent') os.write(args.ready,b'BAR-STARTUP-READY\n');os.close(args.ready);need(os.read(args.ack,16)==b'GO\n','actual preexec observer release');os.close(args.ack);runtime_socket().directory_check();os.chdir(ROOT);c=commands(p,args.invocation)[args.shim];os.execve(c[0],c,environment(p,args.shim)) @@ -413,4 +418,6 @@ def main(): if a.shim:return shim(a) if a.worker:return worker(a) return execute(pathlib.Path(a.admission)) -if __name__=='__main__':raise SystemExit(main()) +if __name__=='__main__': + sys.modules['startup_runner']=sys.modules[__name__] + raise SystemExit(main()) diff --git a/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/test_policy_transport_runner.py b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/test_policy_transport_runner.py new file mode 100644 index 0000000..a6671f8 --- /dev/null +++ b/tests/Broker.NativeProof/RuntimeEvidence/fixtures/seed-attribution-helper/test_policy_transport_runner.py @@ -0,0 +1,102 @@ +"""Pure closed-composition/source-routing controls; no policy/CLR/native execution.""" +import unittest,time,pathlib,tempfile,os,ast,json,hashlib +from unittest.mock import patch,Mock +import seed_policy as s +import policy_transport_runner as r +import startup_runner as native +import mechanics as m +from private_io import Refused +class Composition(unittest.TestCase): + def context(self):return s.PolicyOnlyContext({'policy':{'apphost':'/controlled/apphost','closurePath':'/controlled/closure','closureSha256':'c'*64,'environment':{'PATH':'/usr/bin:/bin'}}},'/controlled/a',Mock(),time.monotonic()+20) + def test_outer_one_use_and_private_grant_before_effects(self): + source=pathlib.Path(r.__file__).read_text();self.assertIn("stat.S_IMODE(info.st_mode)==0o600",source);self.assertIn("info.st_nlink==1",source);self.assertLess(source.index('json_new(consumed,'),source.index('A.mkdir(mode=0o700)')) + with tempfile.TemporaryDirectory()as d: + grant=pathlib.Path(d)/'grant';grant.write_text('{}');grant.chmod(0o600);(grant.parent/(grant.name+'.consumed')).write_text('{}') + with patch.object(r,'profile')as profile,patch.object(r.subprocess,'Popen')as process: + with self.assertRaises(m.Refused):r.execute(grant) + profile.assert_not_called();process.assert_not_called() + def test_malformed_requires_retained_exact_exception_diagnostic(self): + with tempfile.TemporaryDirectory()as d: + root=pathlib.Path(d);(root/'evidence').mkdir();file=root/'evidence/policy-2.failure.stderr.raw' + encoded=b'{malformed';observation={'schema':'fsbar.barc-runtime-evidence-failure-observation/v1','checkpoint':'request-evaluation','kind':'exception'} + def retained(value): + raw=(json.dumps(value)+'\n').encode();file.write_bytes(raw);file.chmod(0o600);pin=m.physical(file);pin['fullWriteFsyncAcknowledged']=True + return {'requestWrittenBytes':len(encoded),'requestSha256':hashlib.sha256(encoded).hexdigest(),'stderr':pin} + with patch.object(r,'ROOT',d): + settlement={'exitCode':2,'forced':False};self.assertEqual(r.require_malformed_refusal(retained(observation),settlement,encoded,2),observation) + for value in [{**observation,'checkpoint':'final-closure'},{**observation,'kind':'refused'},{**observation,'extra':'forged'},{'unknown':True}]: + with self.subTest(value=value),self.assertRaises(m.Refused):r.require_malformed_refusal(retained(value),settlement,encoded,2) + for code,force in [(0,False),(2,True),(-9,True)]: + with self.subTest(code=code,force=force),self.assertRaises(m.Refused):r.require_malformed_refusal(retained(observation),{'exitCode':code,'forced':force},encoded,2) + row=retained(observation);file.write_bytes(b'changed') + with self.assertRaises(m.Refused):r.require_malformed_refusal(row,settlement,encoded,2) + def test_closed_binding(self): + with patch.object(s,'_validate')as validation: + for kind in [s.SeedPolicyContext,s.PolicyOnlyContext]: + log=object.__new__(s.SeedGrowingLog);ctx=object.__new__(kind);self.assertIs(log.bind(ctx),log) + with self.assertRaises(Refused):log.bind(ctx) + validation.assert_called() + class Extension(s.PolicyOnlyContext):pass + for ctx in [object.__new__(Extension),object()]: + with self.assertRaises(Refused):object.__new__(s.SeedGrowingLog).bind(ctx) + def test_exact_seven_element_argv(self): + ctx=self.context();argv=s.policy_argv(ctx.profile['policy'],'d'*64) + self.assertEqual(argv,['/controlled/apphost','--closure-manifest','/controlled/closure','--closure-sha256','c'*64,'--invocation-id','d'*64]) + for invocation in ['',None,'d'*63,'d'*64+';']: + with self.assertRaises(Refused):s.policy_argv(ctx.profile['policy'],invocation) + def test_unsettled_and_fourth_refuse_before_source_or_launch(self): + ctx=self.context() + with patch.object(s,'_validate')as validate,patch.object(s.subprocess,'Popen')as process: + ctx.active=object() + with self.assertRaises(Refused):ctx.launch('a'*64,time.monotonic()+1) + ctx.active=None;ctx.evaluations=3;ctx.reaped=[1,2,3] + with self.assertRaises(Refused):ctx.launch('a'*64,time.monotonic()+1) + validate.assert_not_called();process.assert_not_called() + def test_native_and_policy_only_delegate_same_launch_settlement(self): + ctx=self.context();native_ctx=object.__new__(s.SeedPolicyContext) + with patch.object(s,'launch_policy',return_value='CONTROLLED')as launch: + self.assertEqual(ctx.launch('a'*64,1),'CONTROLLED');self.assertEqual(native_ctx.launch('a'*64,1),'CONTROLLED');self.assertEqual(launch.call_count,2) + with patch.object(s,'settle_policy',return_value=0)as settle: + self.assertEqual(ctx.settle('child',1),0);self.assertEqual(native_ctx.settle('child',1),0);self.assertEqual(settle.call_count,2) + def test_policy_only_does_not_import_or_invoke_native_profile_socket_commands(self): + tree=ast.parse(pathlib.Path(r.__file__).read_text());names={x.module for x in ast.walk(tree)if isinstance(x,ast.ImportFrom)}|{a.name for x in ast.walk(tree)if isinstance(x,ast.Import)for a in x.names} + self.assertNotIn('startup_runner',names);self.assertNotIn('runtime_socket',names) + source=pathlib.Path(r.__file__).read_text();self.assertNotIn('nativeHost',source);self.assertNotIn('engineRuntimeEnvironment',source) + def test_native_shim_and_policy_only_shim_use_shared_function(self): + for module in [native,r]: + tree=ast.parse(pathlib.Path(module.__file__).read_text());shim=next(x for x in tree.body if isinstance(x,ast.FunctionDef)and x.name=='shim') + self.assertTrue(any(isinstance(x,ast.Call)and isinstance(x.func,ast.Name)and x.func.id=='policy_shim'for x in ast.walk(shim))) + def test_wrong_admission_does_not_cross_composition(self): + with self.assertRaises(m.Refused):r.source_binding({'schema':'bar.seed-attribution-admission/v2','operation':'seed-attribution-startup-only'}, {}) + ctx=self.context();ctx.owner=object.__new__(m.LinuxOwner) + with patch.object(m,'load',return_value={'operation':'seed-attribution-startup-only'}),patch.object(r,'source_binding'): + with self.assertRaises(Refused):s._validate(ctx) + def test_unprepared_profile_refuses(self): + with self.assertRaises(m.Refused):r.profile() + def test_policy_only_quota_has_no_socket_exception_and_rejects_foreign_descendant(self): + ctx=self.context();ctx.owner.uncertain=False;ctx.owner.records={};ctx.owner.observe.return_value=[] + with patch.object(m,'quota',return_value={'files':0})as quota,patch.object(s,'_clr',return_value=[]): + self.assertEqual(ctx.pump(time.monotonic()+1),0);self.assertNotIn('runtime_socket',quota.call_args.kwargs) + ctx.owner.observe.return_value=[{'pid':999}] + with self.assertRaises(Refused):ctx.pump(time.monotonic()+1) + def test_one_policy_clr_cap(self): + ctx=self.context();ctx.owner.uncertain=False;ctx.owner.records={};ctx.owner.observe.return_value=[] + with patch.object(m,'quota',return_value={'files':0}),patch.object(s,'_clr',return_value=[1,2]): + with self.assertRaises(Refused):ctx.pump(time.monotonic()+1) + def test_native_pump_still_requires_both_live_actors(self): + owner=Mock();owner.observe.return_value=[];selector=Mock();selector.select.return_value=[] + children={'host':Mock(),'engine':Mock()} + ctx=s.SeedPolicyContext({'policy':{}},'/controlled/a',owner,children,selector,{}, {},time.monotonic()+20) + with patch.object(native,'quota'),patch.object(s,'_clr',return_value=[]): + for role in ['host','engine']: + for child in children.values():child.poll.return_value=None + children[role].poll.return_value=1 + with self.subTest(role=role),self.assertRaises(Refused):ctx.pump(time.monotonic()+1) + def test_exact_policy_source_profile_required(self): + ctx=self.context();ctx.owner=object.__new__(m.LinuxOwner) + with patch.object(m,'load',return_value={'operation':'policy-transport-qualification-only'}),patch.object(r,'source_binding'),patch.object(r,'profile',return_value={'different':'CONTROLLED'}): + with self.assertRaises(Refused):s._validate(ctx) + def test_controlled_worker_writer_and_exact_case_order_are_source_wired(self): + source=pathlib.Path(r.__file__).read_text();self.assertIn('os.O_WRONLY|os.O_APPEND|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW',source);self.assertIn("start_ticks(os.getpid())",source);self.assertIn("log.consume('browser'",source);self.assertIn("ctx.evaluations==1",source);self.assertIn("ctx.evaluations==3",source) + self.assertEqual(r.CASES,['stable-consume','malformed-request','withheld-input']) +if __name__=='__main__':unittest.main()