openlatch-client 0.3.3

OpenLatch runtime enforcement node — the capture-and-enforce adapter that evaluates every covered action against a coding agent's Autonomy Zone before it runs
#!/usr/bin/env python3
"""Verify the exact native npm tarballs before any release package is published.

Checks identity, executable mode, byte equality with this run's artifacts, and
minisign's detached and trusted-comment signatures against the source trust root.
The Linux evaluator must also match the SHA-256 of the artifact readiness tested.
No binary or package lifecycle script is executed here.
"""

import argparse
import hashlib
import json
from pathlib import Path
import re
import struct
import subprocess
import tarfile
import tempfile

ROOT = Path(__file__).resolve().parent.parent
TARGETS = {
    "darwin-arm64": "aarch64-apple-darwin",
    "darwin-x64": "x86_64-apple-darwin",
    "linux-arm64": "aarch64-unknown-linux-gnu",
    "linux-x64": "x86_64-unknown-linux-gnu",
    "win32-x64": "x86_64-pc-windows-msvc",
}


def require(condition, message):
    if not condition:
        raise ValueError(message)


def files_in(path):
    """Read regular members only; reject aliases rather than following archive paths."""
    with tarfile.open(path, "r:gz") as archive:
        files = {}
        for member in archive.getmembers():
            require(member.name not in files, f"duplicate archive member: {member.name}")
            require(member.isfile(), f"non-regular archive member: {member.name}")
            require(member.name.startswith("package/") and
                    all(part not in ("", ".", "..") for part in member.name.split("/")),
                    f"unsafe archive member: {member.name}")
            files[member.name] = (archive.extractfile(member).read(), member.mode)
    return files


def verify_signature(binary, signature, keys):
    """Use minisign's verifier, including its trusted-comment check, for every key."""
    for key in keys:
        result = subprocess.run(
            ["minisign", "-V", "-P", key, "-m", str(binary), "-x", str(signature)],
            capture_output=True, text=True, check=False,
        )
        if result.returncode == 0:
            return
    raise ValueError(f"signature not trusted: {binary.name}")


def verify_format(data, platform):
    """Reject target mixups even when a mislabeled artifact has a valid signature."""
    os_name, arch = platform.split("-")
    if os_name == "linux":
        require(len(data) >= 20 and data[:6] == b"\x7fELF\x02\x01" and
                struct.unpack_from("<H", data, 18)[0] == (183 if arch == "arm64" else 62),
                f"wrong ELF target: {platform}")
    elif os_name == "darwin":
        require(len(data) >= 8 and data[:4] == b"\xcf\xfa\xed\xfe" and
                struct.unpack_from("<I", data, 4)[0] == (0x100000C if arch == "arm64" else 0x1000007),
                f"wrong Mach-O target: {platform}")
    else:
        require(len(data) >= 64 and data[:2] == b"MZ", "missing PE header")
        offset = struct.unpack_from("<I", data, 60)[0]
        require(len(data) >= offset + 6 and data[offset:offset + 6] == b"PE\x00\x00\x64\x86",
                "wrong PE target: win32-x64")


def verify(artifacts, packages, version, binary_sha256, trust_root):
    require(re.fullmatch(r"[0-9a-f]{64}", binary_sha256), "missing readiness binary SHA-256")
    keys = [line.strip() for line in trust_root.read_text().splitlines()
            if line.strip() and not line.lstrip().startswith("#")]
    require(keys, "no committed signing trust roots")
    expected_tarballs = {f"openlatch-client-{platform}-{version}.tgz" for platform in TARGETS}
    expected_tarballs.add(f"openlatch-client-{version}.tgz")
    require({p.name for p in packages.iterdir()} == expected_tarballs, "unexpected or missing tarballs")
    with tempfile.TemporaryDirectory(prefix="native-package-check-") as scratch:
        for platform, target in TARGETS.items():
            files = files_in(packages / f"openlatch-client-{platform}-{version}.tgz")
            manifest = json.loads(files["package/package.json"][0])
            os_name, arch = platform.split("-")
            require(manifest["name"] == f"@openlatch/client-{platform}" and
                    manifest["version"] == version and manifest["os"] == [os_name] and
                    manifest["cpu"] == [arch], f"wrong package identity: {platform}")
            extension = ".exe" if os_name == "win32" else ""
            names = [f"{binary}{extension}" for binary in ("openlatch", "openlatch-hook")]
            expected = {"package/package.json", "package/LICENSE"}
            expected.update(f"package/{name}{suffix}" for name in names for suffix in ("", ".minisig"))
            require(set(files) == expected, f"missing or unexpected native files: {platform}")
            require(files["package/LICENSE"][0], f"empty license: {platform}")
            for name in names:
                data, mode = files[f"package/{name}"]
                require(mode & 0o111, f"binary is not executable: {platform}/{name}")
                verify_format(data, platform)
                original_name = name.removesuffix(extension) if extension else name
                original = artifacts / f"binaries-{target}" / f"{original_name}-{target}{extension}"
                require(data == original.read_bytes(), f"artifact mismatch: {platform}/{name}")
                signature = files[f"package/{name}.minisig"][0]
                require(signature == Path(f"{original}.minisig").read_bytes(),
                        f"signature artifact mismatch: {platform}/{name}")
                binary = Path(scratch) / name
                binary.write_bytes(data)
                sig_path = Path(f"{binary}.minisig")
                sig_path.write_bytes(signature)
                verify_signature(binary, sig_path, keys)
                if platform == "linux-x64" and name == "openlatch":
                    require(hashlib.sha256(data).hexdigest() == binary_sha256,
                            "Linux package differs from readiness-tested binary")

    wrapper = files_in(packages / f"openlatch-client-{version}.tgz")
    manifest = json.loads(wrapper["package/package.json"][0])
    require(manifest["name"] == "@openlatch/client" and manifest["version"] == version,
            "wrong wrapper identity")
    require(manifest["optionalDependencies"] == {
        f"@openlatch/client-{platform}": version for platform in TARGETS
    }, "wrapper must resolve exactly the verified native package versions")
    require(manifest["bin"]["openlatch"] == "lib/index.js" and
            manifest["bin"]["openlatch-hook"] == "lib/openlatch-hook.js", "wrong wrapper entrypoints")
    for name in ["LICENSE", "README.md", "lib/index.js", "lib/openlatch-hook.js",
                 "lib/resolve-binary.js", "lib/postinstall.js"]:
        require(wrapper[f"package/{name}"][0], f"empty wrapper file: {name}")


def main():
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--artifacts", type=Path, required=True)
    parser.add_argument("--packages", type=Path, required=True)
    parser.add_argument("--version", required=True)
    parser.add_argument("--binary-sha256", required=True)
    args = parser.parse_args()
    try:
        verify(args.artifacts, args.packages, args.version, args.binary_sha256,
               ROOT / "signing/openlatch.pub")
    except (OSError, ValueError, KeyError, TypeError, tarfile.TarError) as exc:
        parser.exit(1, f"Native package verification failed: {exc}\n")
    print("Verified five signed native packages and their exact-version wrapper.")


if __name__ == "__main__":
    main()