io_v2_zig_publication.py (5486B)
1 #!/usr/bin/env python3 2 """Real source-owned publication policy on private Zig, with Haskell comparisons.""" 3 import argparse 4 import hashlib 5 import json 6 import subprocess 7 from pathlib import Path 8 from source_order import Runner, field 9 from http_headers import result, tree_list, number 10 from process_rss import run_guarded 11 ROOT = Path(__file__).resolve().parent.parent 12 13 def text(s): return tree_list([number(ord(c)) for c in str(s)]) 14 def main(): 15 p=argparse.ArgumentParser(description=__doc__) 16 p.add_argument('tricu',type=Path);p.add_argument('probe',type=Path);p.add_argument('--directory',type=Path,required=True) 17 args=p.parse_args();d=args.directory.resolve();d.mkdir(parents=True,exist_ok=False) 18 r=Runner(args.tricu,d);bundle=d/'publication.arboricx' 19 r.run('compile',['compile','--file',ROOT/'demos/io-v2/publish.tri','--store',r.store,'--output',bundle]);pin=r.imported(bundle,'import') 20 checks=[] 21 def invoke(label,name,values,expected,compare=False): 22 command=[str(args.probe.resolve()),str(bundle),name,*[str(v) if isinstance(v,int) else 'text:'+str(v) for v in values]] 23 output,peak=run_guarded(command,memory_mib=128,seconds=180) 24 (d/(label+'.log')).write_text(output) 25 actual=bytes(map(int,output.strip())) 26 if expected is not None: assert actual==expected,(label,actual,expected) 27 if compare: 28 flags=['--io'] 29 for i,v in enumerate(values): 30 arg=d/f'{label}-{i}.tree';arg.write_bytes(number(v) if isinstance(v,int) else text(v));flags+=['--arg-tree-file',arg] 31 assert r.invoke(label+'-haskell',pin,name,flags)==actual,label 32 checks.append(dict(label=label,peak_kib=peak)) 33 return actual 34 for size in (0,1,4095,4096,4097,65536,1048576): 35 source=d/f'input-{size}';body=(bytes(range(256))*((size+255)//256))[:size];source.write_bytes(body) 36 target=d/f'objects-{size}';target.mkdir();digest=hashlib.sha256(body).hexdigest() 37 for state in ('new','existing'): 38 invoke(f'{state}-{size}','publish',[source,target,size],result(True,text(digest)),size==4097) 39 assert (target/digest).read_bytes()==body 40 assert (target/digest).stat().st_mode&0o077==0 41 assert sorted(p.name for p in target.iterdir())==[digest] 42 source=d/'source-λ-树';source.write_bytes(b'\0\xffbinary');target=d/'objects-λ-树';target.mkdir() 43 digest=hashlib.sha256(source.read_bytes()).hexdigest() 44 invoke('unicode','publish',[source,target,8],result(True,text(digest)),True) 45 assert (target/digest).read_bytes()==source.read_bytes() 46 source=d/'negative-input';source.write_bytes(b'abc');digest=hashlib.sha256(b'abc').hexdigest() 47 for label,count,winner,message in [('short',4,None,'Incomplete artifact stream'),('excess',2,None,'Artifact exceeds declared length'),('bad-winner',3,b'xyz','Existing artifact digest mismatch'),('short-winner',3,b'ab','Existing artifact length mismatch'),('long-winner',3,b'abcd','Existing artifact length mismatch')]: 48 target=d/label;target.mkdir() 49 if winner is not None:(target/digest).write_bytes(winner) 50 invoke(label,'publish',[source,target,count],result(False,text(message)),True) 51 assert sorted(p.name for p in target.iterdir())==([] if winner is None else [digest]) 52 if winner is not None:assert (target/digest).read_bytes()==winner 53 for name,message in [('earlySuccess','Incomplete artifact stream'),('ignoresWriteFailure','Artifact exceeds declared length'),('emptyChunk','Empty artifact chunk'),('overrideWrite','Incomplete artifact stream'),('failedAfterFull','Producer failed'),('rejectedDestination','Destination rejected')]: 54 target=d/name;target.mkdir();invoke(name,name,[target],result(False,text(message)),True);assert list(target.iterdir())==[] 55 for name,problem in [ 56 ('malformedDestination',tree_list([text('invalid-response'),text('artifact-stream'),text('destination'),text('Expected destination Result'),b'\0'])), 57 ('badDigest',tree_list([text('invalid-response'),text('artifact-stream'),text('digest'),text('Invalid digest reply'),b'\0'])), 58 *[(n,tree_list([text('producer-boundary'),text('artifact-stream'),text('publish'),text('Producer must be sequential'),tree_list([text('outer'),text('inner')])])) for n in ('nestedProducer','forkedProducer')]]: 59 target=d/name;target.mkdir();invoke(name,name,[target],tree_list([text('failed'),problem,b'\0']),True);assert list(target.iterdir())==[] 60 target=d/'invalidChunk';target.mkdir();actual=invoke('invalidChunk','invalidChunk',[target],None,True) 61 assert field(actual,0)==b'\0' and field(actual,1,0,0)==text('write-all') and field(actual,1,0,1,0)==number(0) 62 assert field(actual,1,0,1,1,0,0)==text('invalid-argument');assert list(target.iterdir())==[] 63 target=d/'cancelled';target.mkdir() 64 process=subprocess.run([str(args.probe.resolve()),str(bundle),'cancelled','text:'+str(target)],capture_output=True,timeout=60) 65 assert process.returncode==1 and b'cancelled (reason not forced)' in process.stderr 66 assert list(target.iterdir())==[] and not (d/'escape').exists() 67 checks.append(dict(label='cancelled-no-private-names')) 68 (d/'report.json').write_text(json.dumps(dict(checks=checks,haskell=r.records,probe_sha256=hashlib.sha256(args.probe.read_bytes()).hexdigest()),indent=2)+'\n') 69 print(f'PASS {len(checks)} private Zig source publication/policy controls') 70 if __name__=='__main__':main()