FrameBridge 0.3.4 corresponding-source release

Snapshot assembled only from the signed corresponding-source archive.
Source archive SHA-256: db91a270cdefc4be79056ed38a0b4a16747e1ab130592645eac40fa3809809df
This commit is contained in:
FrameBridge release automation committed 2026-10-29 11:53:40 -04:00
1 parent b8c9b713d8
commit cdd980e1eb
993 files changed
+255481 -1720

No files matched your search

+87
View File
@@ -0,0 +1,87 @@
"""Bind release packages to their corresponding source; never certify runtime QA."""
import hashlib
import json
from pathlib import Path, PurePosixPath
import re
import tarfile
PUBLIC_RELEASE_PROFILES = (
"debian13-amd64-py313", "ubuntu24.04-amd64-py312", "mint22-amd64-py312",
)
def release_source(manifest_path, version, profile_id, current_files, vendor_evidence):
"""Require the same reviewed source and ABI input used by this package.
The manifest and archive are release inputs kept beside one another. Their
signatures and the OS acceptance record are verified outside the builder.
"""
if profile_id not in PUBLIC_RELEASE_PROFILES or not re.fullmatch(r"[0-9]+\.[0-9]+\.[0-9]+", version):
raise RuntimeError("Public release requires a stable version and an official release profile")
manifest_path = Path(manifest_path)
data = json.loads(manifest_path.read_text())
expected_name = "FrameBridge-" + version + "-source.tar.gz"
if (data.get("version"), data.get("status"), data.get("archive")) != (version, "RELEASE_SOURCE_ASSEMBLED", expected_name):
raise RuntimeError("Matching release source manifest is required")
archive = manifest_path.parent / expected_name
if archive.is_symlink() or not archive.is_file():
raise RuntimeError("Matching release source archive is missing")
digest = hashlib.sha256(archive.read_bytes()).hexdigest()
if archive.stat().st_size != data.get("bytes") or digest != data.get("sha256"):
raise RuntimeError("Release source archive hash or size differs from its manifest")
vendors = data.get("vendor_inputs", {}).get("vendors", {})
if set(vendors) != {"cp312", "cp313"}:
raise RuntimeError("Release source must contain the reviewed cp312 and cp313 inputs")
abi = "cp313" if profile_id == "debian13-amd64-py313" else "cp312"
if vendors[abi].get("vendor_sha256") != vendor_evidence.get("vendor_sha256"):
raise RuntimeError("Package vendor input differs from corresponding source")
rows = data.get("files", [])
if not isinstance(rows, list) or any(not isinstance(row, dict) for row in rows):
raise RuntimeError("Invalid release source file manifest")
recorded = {row.get("path"): row.get("sha256") for row in rows}
if len(recorded) != len(rows):
raise RuntimeError("Duplicate release source manifest path")
seen = set()
prefix = "FrameBridge-" + version + "/"
with tarfile.open(archive, "r:gz") as source:
for member in source:
if not member.isfile() or not member.name.startswith(prefix):
raise RuntimeError("Unexpected release source archive member")
relative = member.name[len(prefix):]
if not relative or PurePosixPath(relative).is_absolute() or ".." in PurePosixPath(relative).parts:
raise RuntimeError("Unsafe release source archive path")
if relative in seen or relative not in recorded:
raise RuntimeError("Duplicate or unrecorded release source archive member")
seen.add(relative)
with source.extractfile(member) as stream:
if hashlib.sha256(stream.read()).hexdigest() != recorded[relative]:
raise RuntimeError("Release source archive content differs from its manifest")
if seen != set(recorded):
raise RuntimeError("Release source manifest contains files absent from the archive")
# Bind the ABI claims to the archived bytes, including the ABI not selected
# by this particular package. A manifest field alone is not vendor evidence.
for vendor_abi, expected_prefix in (
("cp313", "source/sources/original-geranas/FrameBridge-Fleet-Hub/vendor"),
("cp312", "source/target-vendors/cp312"),
):
if vendors[vendor_abi].get("path") != expected_prefix:
raise RuntimeError("Unexpected corresponding-source vendor path")
vendor_digest = hashlib.sha256()
# validate_vendor sorts Path objects, whose component ordering differs
# from slash-delimited strings for package/ versus package-1.dist-info/.
for path, file_digest in sorted(recorded.items(), key=lambda row: PurePosixPath(row[0]).parts):
if not path.startswith(expected_prefix + "/"):
continue
relative = path[len(expected_prefix) + 1:]
parts = PurePosixPath(relative).parts
if "__pycache__" in parts or "bin" in parts or relative.endswith(".pyc") or parts[-1] == "FB-ABI-PREPARED.json":
continue
vendor_digest.update(relative.encode() + b"\0")
vendor_digest.update(bytes.fromhex(file_digest))
if vendor_digest.hexdigest() != vendors[vendor_abi].get("vendor_sha256"):
raise RuntimeError("Archived vendor bytes differ from their recorded ABI identity")
for relative, path in current_files.items():
if recorded.get(relative) != hashlib.sha256(path.read_bytes()).hexdigest():
raise RuntimeError("Package source differs from corresponding archive: " + relative)
return {"filename": expected_name, "bytes": data["bytes"], "sha256": digest}