# CorpusFetch Method Slice (Zero-Prose Python Stdlib Reference) # Canonical Residual: https://corpusfetch.com/c/by-what-cryptographic-and-provenance-gates-must-an-instance-verify-signed-artifacts-and-supply-chain-manifests-to-prevent-mirror-compromise-and-downgrade-attacks.md # Remnant Warrant: https://corpusfetch.com/c/by-what-cryptographic-and-provenance-gates-must-an-instance-verify-signed-artifacts-and-supply-chain-manifests-to-prevent-mirror-compromise-and-downgrade-attacks.warrant.json # Markdown SHA-256: 4221b6e82e46e80618429e7c6a987223aa6f0c2b0d9f4675aa56d92babd764fe # Code AST SHA-256: 96c4941bbc0064884f1ea5e9bc69bdd4c9afc0df932471d20c6eecd5e22703ae # Verified Classes: ArtifactIntegrityError # Defensive Guards: 6 fail-closed invariants (zero external deps) import hashlib import hmac import os import shutil import tempfile import urllib.request from pathlib import Path class ArtifactIntegrityError(Exception): '''Raised when an external artifact fails digest or version-floor verification.''' pass def parse_version_tuple(version_str: str) -> tuple[int, ...]: '''Parses a strict numeric version string (e.g., "1.14.2") into a comparable tuple.''' cleaned = version_str.strip().lstrip("v") parts = cleaned.split(".") if not parts or not all(p.isdigit() for p in parts): raise ValueError(f"Invalid numeric version string: {version_str!r}") return tuple(int(p) for p in parts) def fetch_and_verify_artifact( url: str, expected_sha256_hex: str, destination_path: str | Path, *, artifact_version: str | None = None, min_allowed_version: str | None = None, executable: bool = False, max_bytes: int = 128 * 1024 * 1024, ) -> Path: ''' Downloads an external artifact into an inert quarantine file, verifies its monotonic version floor and exact SHA-256 digest in constant time, and atomically promotes it to destination_path only after verification succeeds. ''' # Gate 1: Validate pinned SHA-256 format before making any network call clean_expected = expected_sha256_hex.strip().lower() if len(clean_expected) != 64 or not all(c in "0123456789abcdef" for c in clean_expected): raise ValueError(f"Expected a 64-character hex SHA-256 digest, got {expected_sha256_hex!r}") # Gate 2: Enforce monotonic version floor to block downgrade attacks if artifact_version is not None and min_allowed_version is not None: if parse_version_tuple(artifact_version) < parse_version_tuple(min_allowed_version): raise ArtifactIntegrityError( f"Downgrade attack blocked: artifact version {artifact_version} is older " f"than minimum allowed version {min_allowed_version}." ) dest = Path(destination_path).resolve() dest.parent.mkdir(parents=True, exist_ok=True) # Gate 3: Download to an inert (0600) temporary file in the same directory fd, tmp_name = tempfile.mkstemp(prefix=".quarantine_artifact_", dir=str(dest.parent)) tmp_path = Path(tmp_name) os.chmod(tmp_path, 0o600) hasher = hashlib.sha256() total_bytes = 0 try: req = urllib.request.Request(url, headers={"User-Agent": "CorpusFetch-ProvenanceVerifier/1.0"}) with urllib.request.urlopen(req, timeout=30.0) as resp, os.fdopen(fd, "wb") as out_file: while True: chunk = resp.read(65536) if not chunk: break total_bytes += len(chunk) if total_bytes > max_bytes: raise ArtifactIntegrityError( f"Artifact download exceeded maximum ceiling of {max_bytes} bytes" ) hasher.update(chunk) out_file.write(chunk) out_file.flush() os.fsync(out_file.fileno()) # Gate 4: Constant-time digest verification before promotion actual_hex = hasher.hexdigest().lower() if not hmac.compare_digest(actual_hex, clean_expected): raise ArtifactIntegrityError( f"SHA-256 mismatch for {url}! Expected {clean_expected}, got {actual_hex}." ) # Gate 5: Grant executable bit ONLY after cryptographic verification passes os.chmod(tmp_path, 0o755 if executable else 0o644) tmp_path.replace(dest) return dest except Exception: # Always wipe unverified bytes from disk immediately on any failure tmp_path.unlink(missing_ok=True) raise