# SPDX-License-Identifier: MIT """Hash-screen a bounded Clark file handoff after a verified manual dispatch.""" from __future__ import annotations import argparse from datetime import date from hashlib import sha256 import json from pathlib import Path REQUEST="ab2a8887110cb058d496e0afe1563fe7e42ee260a63608efa2de03a62e58a534";HASH=set("0123456789abcdef") DISPATCH_FIELDS=["schema_version","status","request_sha256","offer_sha256","queue_sha256","role","worksheet_sha256","sent_on","expires_on","provider_message_id_sha256","recipient_address_stored","automatic_contact","message_sent","attachments_sent","attachment_received","submission_created","identity_verified","independence_verified","scientific_validation_claimed","dispatch_sha256"] REQUIRED=["worksheet.csv","validation-draft.json","reviewer-self-check.json","handoff-manifest.json"];OPTIONAL=["validator-output.txt"];LIMIT=1048576 FORBIDDEN=[b"authorization: bearer",b"api_key",b"api-key",b"password",b"-----begin private key",b"client_secret"] def _hash(v):return isinstance(v,str) and len(v)==64 and not(set(v)-HASH) def _dispatch(v): if list(v)!=DISPATCH_FIELDS or v["schema_version"]!="openlab-clark-route-dispatch-receipt-v1" or v["status"]!="manual_route_offer_sent_not_submission" or v["request_sha256"]!=REQUEST:raise ValueError("dispatch identity or fields drift") for f in ["offer_sha256","queue_sha256","worksheet_sha256","provider_message_id_sha256","dispatch_sha256"]: if not _hash(v[f]):raise ValueError("dispatch hash invalid") body={k:v[k] for k in DISPATCH_FIELDS[:-1]};expected=sha256(json.dumps(body,ensure_ascii=False,separators=(",",":"),sort_keys=True).encode()).hexdigest() if v["dispatch_sha256"]!=expected:raise ValueError("dispatch seal mismatch") if v["recipient_address_stored"] is not False or v["automatic_contact"] is not False or v["message_sent"] is not True or v["attachments_sent"]!=0 or v["attachment_received"] is not False or v["submission_created"] is not False or v["identity_verified"] is not False or v["independence_verified"] is not False or v["scientific_validation_claimed"] is not False:raise ValueError("dispatch boundary drift") return v def screen(dispatch,directory,received_on): dispatch=_dispatch(dispatch);root=Path(directory) if not root.is_dir() or root.is_symlink():raise ValueError("regular intake directory required") try:received=date.fromisoformat(received_on);sent=date.fromisoformat(dispatch["sent_on"]);expires=date.fromisoformat(dispatch["expires_on"]) except (TypeError,ValueError) as e:raise ValueError("intake date invalid") from e if receivedexpires:raise ValueError("intake outside dispatched offer validity") children=list(root.iterdir());names=sorted(x.name for x in children);allowed=set(REQUIRED+OPTIONAL) if not set(REQUIRED)<=set(names) or set(names)-allowed or len(names)!=len(set(names)):raise ValueError("intake file set invalid") files=[];total=0 for path in sorted(children,key=lambda x:x.name): if path.is_symlink() or not path.is_file():raise ValueError("only regular top-level files allowed") data=path.read_bytes();total+=len(data) if len(data)==0 or len(data)>LIMIT or total>LIMIT:raise ValueError("intake size boundary exceeded") try:text=data.decode("utf-8") except UnicodeDecodeError as e:raise ValueError("all intake files must be UTF-8 text") from e lower=data.lower() if any(marker in lower for marker in FORBIDDEN):raise ValueError("credential-like content refused") if path.suffix==".json": try:json.loads(text) except json.JSONDecodeError as e:raise ValueError("JSON intake file invalid") from e files.append({"name":path.name,"bytes":len(data),"sha256":sha256(data).hexdigest()}) if len({item["sha256"] for item in files})!=len(files):raise ValueError("intake files must have distinct content hashes") result={"schema_version":"openlab-clark-attachment-intake-receipt-v1","status":"files_hash_screened_for_private_curator_review_not_submission","request_sha256":REQUEST,"dispatch_sha256":dispatch["dispatch_sha256"],"role":dispatch["role"],"worksheet_sha256":dispatch["worksheet_sha256"],"received_on":received_on,"files":files,"total_bytes":total,"raw_content_copied_to_receipt":False,"sender_address_stored":False,"production_database_used":False,"submission_created":False,"identity_verified":False,"independence_verified":False,"scientific_validation_claimed":False,"manual_private_curator_review_required":True} result["intake_sha256"]=sha256(json.dumps(result,ensure_ascii=False,separators=(",",":"),sort_keys=True).encode()).hexdigest();return result def main(): p=argparse.ArgumentParser();p.add_argument("dispatch");p.add_argument("directory");p.add_argument("--received-on",required=True);p.add_argument("--out",required=True);a=p.parse_args();r=screen(json.loads(Path(a.dispatch).read_text(encoding="utf-8")),a.directory,a.received_on);Path(a.out).write_text(json.dumps(r,ensure_ascii=False,indent=2)+"\n",encoding="utf-8");print(json.dumps(r,ensure_ascii=False)) if __name__=="__main__":main()