#!/usr/bin/env python3
"""Create the static harness inventory and seal; never handles customer images."""
from __future__ import annotations
import hashlib, json, os, stat, tempfile
from datetime import datetime, timezone
from pathlib import Path

ROOT=Path(__file__).resolve().parent
OUTPUTS={"inventory.json","SEAL.json","independent-verification.json","capture-receipt.redacted.json"}
EXPECTED={"README.md","capture-contract.json","capture.py","dry-run.json","exact-future-command.txt","independent_verify.py","seal_harness.py","test-results.txt","test_capture.py"}
def sha(data:bytes)->str:return hashlib.sha256(data).hexdigest()
def canon(v:object)->bytes:return (json.dumps(v,ensure_ascii=True,sort_keys=True,separators=(",",":"))+"\n").encode()
def atomic(path:Path,data:bytes)->None:
    fd,name=tempfile.mkstemp(prefix=f".{path.name}.",dir=ROOT)
    try:
        os.fchmod(fd,0o600)
        view=memoryview(data)
        while view:
            count=os.write(fd,bytes(view))
            if count<=0:raise RuntimeError("short seal write")
            view=view[count:]
        os.fsync(fd);os.close(fd);fd=-1;os.replace(name,path)
        dfd=os.open(ROOT,os.O_RDONLY|os.O_DIRECTORY)
        try:os.fsync(dfd)
        finally:os.close(dfd)
    finally:
        if fd>=0:os.close(fd)
        try:os.unlink(name)
        except FileNotFoundError:pass
def main()->None:
    actual={p.name for p in ROOT.iterdir() if p.is_file() and p.name not in OUTPUTS and not p.name.startswith(".")}
    if actual!=EXPECTED:raise RuntimeError(f"static artifact mismatch: missing={EXPECTED-actual}, extra={actual-EXPECTED}")
    entries=[]
    for name in sorted(EXPECTED):
        path=ROOT/name
        if path.is_symlink() or not path.is_file():raise RuntimeError(f"unsafe artifact: {name}")
        raw=path.read_bytes();entries.append({"bytes":len(raw),"mode":f"{stat.S_IMODE(path.stat().st_mode):04o}","path":name,"sha256":sha(raw)})
    inventory={"entries":entries,"schema":"task26-customer-surface-capture-inventory-v1"}
    inventory_raw=canon(inventory);atomic(ROOT/"inventory.json",inventory_raw)
    contract_raw=(ROOT/"capture-contract.json").read_bytes()
    seal={"contract_sha256":sha(contract_raw),"inventory_sha256":sha(inventory_raw),"lifecycle_evidence_sha256":"6e507907ea1b8595ab65c4052d67d71a3215eb37f113036b39537374a13c9c37","lifecycle_seal_sha256":"50e7556e58a876d8136fbfb2023ede8bcb46ac816d97d4b85e1d0559f463d008","schema":"task26-customer-surface-capture-seal-v1","sealed_at_utc":datetime.now(timezone.utc).isoformat().replace("+00:00","Z"),"sealed_file_count":len(entries),"state":"PASS_SEALED_AWAITING_FINAL_RUN_IMAGE"}
    atomic(ROOT/"SEAL.json",canon(seal))
if __name__=="__main__":main()
