E2 is FEASIBLE for the measured matrix. The initial private integration candidate is BUILDABLE; its accepted comment delta is NOT REBUILT. STEP20C remains NEXT and production multi-output remains NOT YET SUPPORTED.
194 lines
13 KiB
Python
194 lines
13 KiB
Python
#!/usr/bin/env python3
|
|
"""Prospective E2 handoff, derived from static-nested-runtime/handoff.py.
|
|
|
|
WHY: historical ACCEPTED cannot sign changed runner bytes.
|
|
CONTRACT: genuine independent review binds final sources, receipts and owner.
|
|
INVARIANT: preflight reads only; launch consumption is exclusive and durable.
|
|
"""
|
|
import ast
|
|
import json
|
|
import os
|
|
from pathlib import Path
|
|
import secrets
|
|
import shutil
|
|
import stat
|
|
import subprocess
|
|
import sys
|
|
import tempfile
|
|
from support import sha,verify,environment
|
|
from model import require
|
|
from ledger import LIMITS,valid
|
|
from transition import source_bindings,SOURCE_FILES
|
|
|
|
HERE=Path(__file__).resolve().parent
|
|
SOURCE_ROOT=Path('/home/fy59/Documents/Development/swayfx-mosaic/tooling/probes/step20c-static-e2-completion')
|
|
TICKET='SWAYFX_MOSAIC_STEP20C_E2_COMPLETION_AND_PRIVATE_INTEGRATION_BATCH_V1'
|
|
REGISTRY=Path('/home/fy59/swayfx-mosaic-e2-completion-v1.owner')
|
|
REGISTRATION=REGISTRY.with_suffix('.registration.json')
|
|
SPENT=REGISTRY.with_suffix('.launch-consumed.json')
|
|
OLD_LAB=Path('/home/fy59/swayfx-mosaic-static-nested-runtime-pvn0osxm')
|
|
BINARY=Path('/home/fy59/swayfx-mosaic-static-runtime-hm5kbdkt/stage-static/usr/bin/swayfx-mosaic')
|
|
BINARY_SHA='f82557c1a9978a5e9665b9b4291b74880253725359e3df1c5b8d554921f7603b'
|
|
BUILD_ID='942db64269640778ee433e5970ba1100bc60f94c'
|
|
WLROOTS=Path('/usr/lib/libwlroots-0.20.so')
|
|
WLROOTS_SHA='7edca9a7d65855addda68e29ba5db94d57c803eb5fa7d0f86db3136b90ca9837'
|
|
MARKER='E2_COMPLETION_OFFLINE=READY_FOR_REVIEW'
|
|
|
|
|
|
def read(path):return json.loads(Path(path).read_text())
|
|
|
|
|
|
def exclusive(path,data):
|
|
path=Path(path)
|
|
fd=os.open(path,os.O_WRONLY|os.O_CREAT|os.O_EXCL|os.O_NOFOLLOW,0o600)
|
|
with os.fdopen(fd,'w') as out:
|
|
out.write(data if isinstance(data,str) else json.dumps(data,indent=2)+'\n');out.flush();os.fsync(out.fileno())
|
|
fd=os.open(path.parent,os.O_RDONLY|os.O_DIRECTORY)
|
|
try:os.fsync(fd)
|
|
finally:os.close(fd)
|
|
|
|
|
|
def regular(path,mode=None):
|
|
p=Path(path);s=p.lstat()
|
|
require(stat.S_ISREG(s.st_mode) and s.st_uid==os.getuid(),'owned-regular-file:'+str(p))
|
|
if mode is not None:require(stat.S_IMODE(s.st_mode)==mode,'file-mode:'+str(p))
|
|
|
|
|
|
def copy_exact(source,dest):
|
|
regular(source)
|
|
with Path(source).open('rb') as src,Path(dest).open('xb') as out:
|
|
shutil.copyfileobj(src,out);out.flush();os.fsync(out.fileno())
|
|
Path(dest).chmod(stat.S_IMODE(Path(source).stat().st_mode))
|
|
require(sha(source)==sha(dest),'copy-exact')
|
|
return dict(source=str(source),destination=str(dest),sha256=sha(source))
|
|
|
|
|
|
def source_map():return {p.name:sha(p) for p in SOURCE_ROOT.iterdir() if p.is_file()}
|
|
|
|
|
|
def immutable_paths(lab):
|
|
paths=[p for root in ('fixture','client-source','offline') for p in (lab/root).iterdir() if p.is_file()]
|
|
paths += [lab/n for n in ('swayfx-mosaic','nested-client','pointer-daemon','static-reference','campaign-owner')]
|
|
paths += [lab/'results/binary-identity.json',*[lab/'raw'/(name+'.json') for name in ('ELF','symbols','relocations')],BINARY,WLROOTS.resolve(),REGISTRY]
|
|
paths += [Path(p) for p in SOURCE_FILES.values()]
|
|
paths += [p for p in SOURCE_ROOT.iterdir() if p.is_file()]
|
|
require(len(paths)==len(set(paths)),'unique-manifest-paths')
|
|
return sorted(paths)
|
|
|
|
|
|
def prepare(offline):
|
|
from gate import validate_gate
|
|
offline=Path(offline).resolve();gate=validate_gate(offline/'offline-gate.json')
|
|
require(not any(p.exists() for p in (REGISTRY,REGISTRATION,SPENT)),'ticket-already-registered')
|
|
require(sha(BINARY)==BINARY_SHA and sha(WLROOTS)==WLROOTS_SHA,'binary-wlroots-identities')
|
|
lab=Path(tempfile.mkdtemp(prefix='swayfx-mosaic-e2-completion-',dir='/home/fy59'));lab.chmod(0o700)
|
|
for n in ('results','raw','fixture','client-source','offline'):(lab/n).mkdir()
|
|
token=secrets.token_hex(32)
|
|
exclusive(REGISTRY,str(lab)+'\n');exclusive(lab/'campaign-owner',str(REGISTRY)+'\n')
|
|
transfers=[]
|
|
for p in sorted(HERE.iterdir()):
|
|
if p.is_file():transfers.append(copy_exact(p,lab/'fixture'/p.name))
|
|
for name in ('offline-gate.json','test-receipts.json','replay.json','source-audit.json'):
|
|
transfers.append(copy_exact(offline/name,lab/'offline'/name))
|
|
for n in ('swayfx-mosaic','nested-client','pointer-daemon','static-reference'):
|
|
transfers.append(copy_exact(BINARY if n=='swayfx-mosaic' else OLD_LAB/n,lab/n));regular(lab/n,0o755)
|
|
# Actual prepared static_cross sources and generated protocols, not rebuilt.
|
|
for p in sorted((OLD_LAB/'client-build').iterdir()):
|
|
if p.suffix in ('.c','.h'):transfers.append(copy_exact(p,lab/'client-source'/p.name))
|
|
contract=read(HERE/'client-contract.json')
|
|
require(sha(lab/'client-source/nested-client.c')==contract['adapted_nested_sha256'],'actual-static-cross-source')
|
|
for name,digest in contract['protocols'].items():require(sha(lab/'client-source'/name)==digest,'actual-protocol-source')
|
|
identity={}
|
|
for label,argv in [('ELF',['readelf','-hW','-nW','-dW',str(lab/'swayfx-mosaic')]),
|
|
('symbols',['nm',str(lab/'swayfx-mosaic')]),('relocations',['ldd','-r',str(lab/'swayfx-mosaic')])]:
|
|
r=subprocess.run(argv,env=environment(),capture_output=True,text=True,timeout=30)
|
|
exclusive(lab/'raw'/(label+'.json'),dict(argv=argv,exit=r.returncode,stdout=r.stdout,stderr=r.stderr))
|
|
require(r.returncode==0,'identity-command');identity[label]=r.stdout
|
|
require(BUILD_ID in identity['ELF'] and 'ELF64' in identity['ELF'] and
|
|
all(s not in identity['ELF'] for s in ('libscenefx','(RPATH)','(RUNPATH)')),'ELF-static-contract')
|
|
require(all(' T '+n in identity['symbols'] for n in ('wlr_scene_tree_set_clip','wlr_scene_tree_get_clip')),'clip-symbols')
|
|
require(str(WLROOTS.resolve()) in identity['relocations'] and
|
|
all(s not in identity['relocations'] for s in ('libscenefx','undefined symbol','not found')),'resolved-libraries')
|
|
exclusive(lab/'results/binary-identity.json',dict(status='PASS',build_id=BUILD_ID,binary_sha256=BINARY_SHA,
|
|
wlroots_sha256=WLROOTS_SHA,raw={n:sha(lab/'raw'/(n+'.json')) for n in identity}))
|
|
exclusive(lab/'results/fixture-freeze-sha256.txt',''.join(sha(p)+' '+str(p)+'\n' for p in immutable_paths(lab)))
|
|
frozen=verify(lab/'results/fixture-freeze-sha256.txt')
|
|
registration=dict(ticket=TICKET,lab=str(lab),owner_registry=str(REGISTRY),uid=os.getuid(),token=token,
|
|
fixture_sha256=frozen['sha256'],binary=str(BINARY),binary_sha256=BINARY_SHA,wlroots_sha256=WLROOTS_SHA)
|
|
exclusive(REGISTRATION,registration);exclusive(lab/'results/registration.json',registration)
|
|
auth={**registration,'registered_lab':str(lab),'scope':'one-new-static-e2-completion-headless-run','explicit_user_authorization':True}
|
|
exclusive(lab/'results/authorization.json',auth)
|
|
exclusive(lab/'results/budget.json',dict(limits=LIMITS,used=dict.fromkeys(LIMITS,0),events=[]))
|
|
exclusive(lab/'results/offline-gate.json',dict(marker=MARKER,status='READY_FOR_REVIEW',fixture_sha256=frozen['sha256'],
|
|
offline_gate_sha256=sha(lab/'offline/offline-gate.json')))
|
|
exclusive(lab/'results/runtime-handoff.json',dict(status='PREPARED_FOR_INDEPENDENT_REVIEW',ticket=TICKET,
|
|
lab=str(lab),fixture=frozen,transfers=transfers,source_sha256=source_map(),source_contract=source_bindings(),
|
|
gate_sha256=sha(lab/'offline/offline-gate.json'),authorization_sha256=sha(lab/'results/authorization.json'),
|
|
registration_sha256=sha(REGISTRATION),historical_review='does not accept changed runner',run_reserved=False))
|
|
print('LAB='+str(lab));return lab
|
|
|
|
|
|
def preflight(lab,authorization,review=True,consumed=False):
|
|
"""Read-only. review=False is prospective preparation, never dispatch."""
|
|
from gate import validate_gate
|
|
lab=Path(lab).resolve();authorization=Path(authorization)
|
|
require(not sys.flags.optimize,'assertions-required')
|
|
require(lab!=OLD_LAB and lab.name.startswith('swayfx-mosaic-e2-completion-'),'fresh-ticket-lab')
|
|
require(lab.stat().st_uid==os.getuid() and stat.S_IMODE(lab.stat().st_mode)==0o700,'lab-owner-mode')
|
|
for p in (REGISTRY,REGISTRATION,lab/'campaign-owner',authorization):regular(p,0o600)
|
|
require(REGISTRY.read_text().strip()==str(lab) and (lab/'campaign-owner').read_text().strip()==str(REGISTRY),'exclusive-owner')
|
|
auth=read(authorization);registration=read(REGISTRATION)
|
|
require(registration==read(lab/'results/registration.json'),'durable-registration-copy')
|
|
require(auth=={**registration,'registered_lab':str(lab),'scope':'one-new-static-e2-completion-headless-run',
|
|
'explicit_user_authorization':True},'exact-authorization')
|
|
require(auth['ticket']==TICKET and auth['lab']==str(lab) and auth['owner_registry']==str(REGISTRY)
|
|
and auth['uid']==os.getuid() and len(auth['token'])==64,'ticket-lab-token')
|
|
require(auth['binary']==str(BINARY) and auth['binary_sha256']==BINARY_SHA and auth['wlroots_sha256']==WLROOTS_SHA,
|
|
'authorized-identities')
|
|
require(sha(BINARY)==sha(lab/'swayfx-mosaic')==BINARY_SHA and sha(WLROOTS)==WLROOTS_SHA,'actual-identities')
|
|
require(not (lab/'run').exists() and not (lab/'run.lock').exists(),'unconsumed-runtime')
|
|
require(not any(stat.S_ISSOCK(p.lstat().st_mode) for p in lab.rglob('*')),'no-existing-sockets')
|
|
manifest=lab/'results/fixture-freeze-sha256.txt'
|
|
frozen=verify(manifest)
|
|
require(manifest.read_text()==''.join(sha(p)+' '+str(p)+'\n' for p in immutable_paths(lab)),'complete-exact-manifest')
|
|
require({p.name:sha(p) for p in (lab/'fixture').iterdir() if p.is_file()}==source_map(),'installed-final-fixture')
|
|
require(auth['fixture_sha256']==frozen['sha256'],'authorization-manifest')
|
|
handoff=read(lab/'results/runtime-handoff.json')
|
|
require(handoff['ticket']==TICKET and handoff['lab']==str(lab) and handoff['fixture']==frozen and
|
|
handoff['source_sha256']==source_map() and handoff['source_contract']==source_bindings() and
|
|
handoff['authorization_sha256']==sha(authorization) and handoff['registration_sha256']==sha(REGISTRATION),
|
|
'handoff-final-bindings')
|
|
require(bool(handoff['transfers']) and len({row['destination'] for row in handoff['transfers']})==len(handoff['transfers']),'nonempty-unique-transfers')
|
|
for row in handoff['transfers']:require(sha(row['source'])==sha(row['destination'])==row['sha256'],'transfer-changed')
|
|
gate=validate_gate(lab/'offline/offline-gate.json')
|
|
require(handoff['gate_sha256']==sha(lab/'offline/offline-gate.json'),'handoff-gate-binding')
|
|
require(read(lab/'results/offline-gate.json')==dict(marker=MARKER,status='READY_FOR_REVIEW',fixture_sha256=frozen['sha256'],
|
|
offline_gate_sha256=sha(lab/'offline/offline-gate.json')),'derived-gate')
|
|
budget=valid(read(lab/'results/budget.json'));require(not any(budget['used'].values()) and not budget['events'],'ledger-unreserved')
|
|
identity=read(lab/'results/binary-identity.json')
|
|
require(identity['status']=='PASS' and identity['build_id']==BUILD_ID and identity['binary_sha256']==BINARY_SHA
|
|
and identity['wlroots_sha256']==WLROOTS_SHA,'identity-receipt')
|
|
for n,digest in identity['raw'].items():require(sha(lab/'raw'/(n+'.json'))==digest,'raw-identity-binding')
|
|
expected_spent=dict(ticket=TICKET,lab=str(lab),token=auth['token'],fixture_sha256=frozen['sha256'],authorization_sha256=sha(authorization))
|
|
if consumed:require(SPENT.exists() and read(SPENT)==expected_spent,'runner-exact-consumption')
|
|
else:require(not SPENT.exists(),'ticket-launch-already-consumed')
|
|
if review:
|
|
reviewed=read(lab/'results/handoff-review.json')
|
|
require(reviewed.get('status')=='ACCEPTED' and reviewed.get('independent') is True and reviewed.get('read_only') is True
|
|
and reviewed.get('scope')=='STATIC_E2_COMPLETION_FINAL_BYTES' and reviewed.get('blockers')==[],
|
|
'genuine-independent-review-required')
|
|
require(reviewed['fixture_sha256']==frozen['sha256'] and reviewed['source_sha256']==source_map()
|
|
and reviewed['runtime_handoff_sha256']==sha(lab/'results/runtime-handoff.json')
|
|
and reviewed['authorization_sha256']==sha(authorization) and reviewed['registration_sha256']==sha(REGISTRATION)
|
|
and reviewed['gate_sha256']==sha(lab/'offline/offline-gate.json'),'review-final-bindings')
|
|
regular(reviewed['report_file']);require(sha(reviewed['report_file'])==reviewed['report_sha256'],'review-report-bytes')
|
|
return dict(status='PASS',ticket=TICKET,lab=str(lab),fixture=frozen,token=auth['token'],
|
|
review='ACCEPTED' if review else 'PENDING_INDEPENDENT_REVIEW',run_reserved=False)
|
|
|
|
if __name__=='__main__':
|
|
import argparse
|
|
p=argparse.ArgumentParser();p.add_argument('action',choices=['prepare','preflight']);p.add_argument('path',type=Path);a=p.parse_args()
|
|
if a.action=='prepare':prepare(a.path)
|
|
else:
|
|
result=preflight(a.path,a.path/'results/authorization.json');exclusive(a.path/'results/preflight.json',result)
|
|
print('E2_COMPLETION_PREFLIGHT=PASS')
|