the-custodian/docs/changes/2026-11-01-scanner-json-digest/native-r5/rollout.py
codex dfd7ee5f30
All checks were successful
CI Smoke / host-smoke (push) Successful in 0s
CI Smoke / container-smoke (push) Successful in 2s
Reject generated-only commits / generated-commit-guard (push) Successful in 13s
Record approved scanner revision 5 and verified cached-stream correction
2026-11-02 11:31:44 +01:00

50 lines
2.4 KiB
Python

"""R5 envelope: consume/count cached-stage stdin; preserve approved R4 behavior."""
from pathlib import Path
import argparse,hashlib,importlib.util,json
HERE=Path(__file__).resolve().parent
BASE=HERE.parent/'native-r4'
OUTPUT=Path('/tmp/forge-scanner-rollout-r5-receipt.json')
R4='64c73100f2347470fda1b8b3194dbf6a8009291d9d80223af463b3c5ecab52fd'
def sha(raw):return hashlib.sha256(raw).hexdigest()
def base_module():
s=importlib.util.spec_from_file_location('approved_r4_library',BASE/'rollout.py');b=importlib.util.module_from_spec(s);s.loader.exec_module(b)
if b.verify_packet()!=R4:raise RuntimeError('reviewed-r4-packet-drift')
return b
def verify_packet():
raw=(HERE/'packet.json').read_bytes();p=json.loads(raw)
for name,digest in p['files'].items():
if Path(name).name!=name or sha((HERE/name).read_bytes())!=digest:raise RuntimeError('r5-packet-drift')
base_module();return sha(raw)
def make_runner(base,module):
class Rollout(base.make_runner(module)):
def shell(self,pod,script,args=(),data=None,timeout=90):
staging=script==(base.ORIGINAL/'stage.sh').read_text()
if staging:script=(HERE/'stage.sh').read_text()
self._cached_stage_call=staging
try:return super().shell(pod,script,args,data,timeout)
finally:self._cached_stage_call=False
def event(self,name,**fields):
if name=='command-failed' and getattr(self,'_cached_stage_call',False):fields['operation']='artifact-staging'
return super().event(name,**fields)
return Rollout
def main():
p=argparse.ArgumentParser(description=__doc__);p.add_argument('--approved-digest',required=True)
p.add_argument('--binary',type=Path,default=Path('/tmp/sync-scanner-candidate/receive-secret-scan-candidate'));a=p.parse_args()
digest=verify_packet()
if a.approved_digest!=digest:raise RuntimeError('exact-founder-acknowledgement-required')
b=base_module();m=b.support();m.RECEIPT=OUTPUT;c=json.loads((b.ORIGINAL/'inputs.json').read_bytes())
runner=make_runner(b,m)(c);runner.receipt.update(revision=5,packet_sha256=digest,reused_r4_packet_sha256=R4,mode='apply')
with OUTPUT.open('x') as f:f.write(json.dumps(runner.receipt)+'\n')
runner.apply(a.binary)
if __name__=='__main__':
try:main()
except Exception as e:
print(json.dumps({'result':'refused-or-unverified','reason':str(e) if isinstance(e,RuntimeError) else type(e).__name__}))
raise SystemExit(1)