Files
jason.woltje 4ac6f13bcf fix(case2): row 227 R4 source overlay as reviewed (packet 4eb60915, #1728)
Commits the 5 product paths and 7 gate helpers of the row 227 R4 source overlay on top of HEAD 5a0c801cb. scripts/case2/console.mjs is already committed at HEAD and is not part of this commit. The R4 independent review is sha256 6667baaa6af9d6d78a3ec7c64d9f3163ecbc350b94050f62899d9c01deabe002, verdict APPROVE source-only. Packet hashes: PACKET.sha256 4eb60915b2144137df9b5a42afd0c5b266718d71de051fb8be53a27430a2cad4, CURRENT-SOURCE.sha256 0cfd47c2073bc18a3ba7bff1ce6fdf39fe33a64b7fca209be71517b9feb89020. The 12 committed files match the review hash table, the applied overlay JSON (size, mode, hash) and the saved overlay tar. No scripts/test-case2.sh run exists on these bytes.
2026-11-02 13:39:29 -06:00

76 lines
4.0 KiB
Python

# Owned gate evidence only; raw bytes are retained before any control/registry parse.
import os,json,time,hashlib,stat
from pathlib import Path
class Evidence:
def __init__(self,root):
self.root=Path(root);self.root.mkdir(parents=True,exist_ok=False)
(self.root/'raw-inputs').mkdir();self.failures=[];self.unknown=False;self.inventory=[];self.saved=set()
self.journal=(self.root/'failure-journal.jsonl').open('x',buffering=1)
self.final=(self.root/'result.json').open('x');self.cleanup=(self.root/'cleanup.json').open('x')
def fail(self,code,unknown=True):
if code not in self.failures:self.failures.append(code)
self.unknown=self.unknown or unknown
try:self.journal.write(json.dumps(dict(at=time.time(),code=code))+'\n');self.journal.flush();os.fsync(self.journal.fileno())
except Exception:
try:os.write(2,b'gate-evidence-journal-failed\n')
except Exception:pass
def write(self,name,data):
try:
p=self.root/name;p.parent.mkdir(parents=True,exist_ok=True)
if not isinstance(data,bytes):data=(json.dumps(data,indent=2)+'\n').encode()
with p.open('wb') as f:f.write(data);f.flush();os.fsync(f.fileno())
return True
except Exception as exc:self.fail('evidence-write-'+type(exc).__name__);return False
def raw(self,path,category,missing_ok=False):
path=Path(path);fd=None
# Private capture limits, not product/API limits. The full admitted dependency manifest
# gets128MiB; admission8MiB and changing run logs64MiB; native/control records1MiB.
limit={'frozen-manifest':128*1024*1024,'admission':8*1024*1024,'run-control':64*1024*1024}.get(category,1024*1024)
def refuse(reason,info=None):
row=dict(path=str(path),category=category,disposition=reason,limit=limit,
mode=info.st_mode if info else None,size=info.st_size if info else None)
name=hashlib.sha256(json.dumps(row,sort_keys=True).encode()).hexdigest()
self.write('raw-refusals/'+name+'.json',row);self.inventory.append(row);self.fail('raw-'+reason)
try:
# Nonblocking open cannot wait for a FIFO writer; descriptor validation precedes READ.
fd=os.open(path,os.O_RDONLY|os.O_NOFOLLOW|os.O_NONBLOCK|os.O_CLOEXEC)
info=os.fstat(fd)
if not stat.S_ISREG(info.st_mode):refuse('nonregular-refused',info);return None
if info.st_size<0 or info.st_size>limit:refuse('size-refused',info);return None
# Read only the descriptor's initial finite size, never a growing stream through EOF.
chunks=[];remaining=info.st_size
while remaining:
block=os.read(fd,min(remaining,65536))
if not block:break
chunks.append(block);remaining-=len(block)
data=b''.join(chunks);after=os.fstat(fd)
sha=hashlib.sha256(data).hexdigest();key=(str(path),sha)
if key not in self.saved:
if self.write('raw-inputs/'+category+'/'+sha+'.raw',data):
self.saved.add(key);self.inventory.append(dict(path=str(path),category=category,sha256=sha,bytes=len(data),
initialSize=info.st_size,observedSizeAfter=after.st_size,
disposition='snapshot' if len(data)==info.st_size==after.st_size else 'finite-prefix-snapshot'))
return data
except FileNotFoundError:
if not missing_ok:self.fail('required-raw-input-missing')
except Exception as exc:refuse('capture-'+type(exc).__name__)
finally:
if fd is not None:
try:os.close(fd)
except Exception as exc:self.fail('raw-close-'+type(exc).__name__)
return None
def parse(self,path,category,missing_ok=False):
raw=self.raw(path,category,missing_ok)
if raw is None:return None
try:return json.loads(raw)
except Exception as exc:self.fail('parse-'+category+'-'+type(exc).__name__);return None
def inventory_write(self):return self.write('raw-inventory.json',self.inventory)
def reserved(self,handle,data):
try:
handle.seek(0);handle.truncate();handle.write(json.dumps(data,indent=2)+'\n');handle.flush();os.fsync(handle.fileno());return True
except Exception as exc:
self.fail('final-receipt-'+type(exc).__name__)
try:os.write(2,b'gate-final-receipt-failed; nonacceptance\n')
except Exception:pass
return False