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:
1 parent
b8c9b713d8
commit
cdd980e1eb
993 files changed
+255481
-1720
No files matched your search
@@ -0,0 +1,133 @@
|
||||
"""Release assembly rejects stale or mismatched corresponding source."""
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
from pathlib import Path
|
||||
import sys
|
||||
import tarfile
|
||||
import tempfile
|
||||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
sys.path.insert(0, str(Path(__file__).resolve().parents[1] / "packaging"))
|
||||
import build_expanded
|
||||
from release_metadata import release_source
|
||||
|
||||
|
||||
class PublicReleaseSourceTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
self.tmp = tempfile.TemporaryDirectory()
|
||||
self.addCleanup(self.tmp.cleanup)
|
||||
self.root = Path(self.tmp.name)
|
||||
self.file = self.root / "module.py"
|
||||
self.file.write_text("# reviewed release source\n")
|
||||
self.archive = self.root / "FrameBridge-0.3.4-source.tar.gz"
|
||||
self.vendor_paths = {
|
||||
"cp313": "source/sources/original-geranas/FrameBridge-Fleet-Hub/vendor",
|
||||
"cp312": "source/target-vendors/cp312",
|
||||
}
|
||||
vendor_data = b"# reviewed vendor input\n"
|
||||
self.vendor_files = {"module.py": vendor_data,
|
||||
"package/__init__.py": b"# package\n",
|
||||
"package-1.dist-info/METADATA": b"Name: package\nVersion: 1\n"}
|
||||
self.payloads = {"source/module.py": self.file.read_bytes(),
|
||||
**{path + "/" + relative: data for path in self.vendor_paths.values()
|
||||
for relative, data in self.vendor_files.items()}}
|
||||
self.write_archive()
|
||||
# The reviewed vendor format uses Path component ordering. In particular
|
||||
# package/__init__.py comes before package-1.dist-info/METADATA.
|
||||
digest = hashlib.sha256()
|
||||
for relative in ("module.py", "package/__init__.py", "package-1.dist-info/METADATA"):
|
||||
digest.update(relative.encode() + b"\0")
|
||||
digest.update(hashlib.sha256(self.vendor_files[relative]).digest())
|
||||
self.vendor = {"vendor_sha256": digest.hexdigest()}
|
||||
self.data = {
|
||||
"version": "0.3.4", "status": "RELEASE_SOURCE_ASSEMBLED",
|
||||
"archive": self.archive.name, "bytes": self.archive.stat().st_size,
|
||||
"sha256": hashlib.sha256(self.archive.read_bytes()).hexdigest(),
|
||||
"vendor_inputs": {"vendors": {abi: {**self.vendor, "path": path} for abi, path in self.vendor_paths.items()}},
|
||||
"files": [{"path": path, "sha256": hashlib.sha256(data).hexdigest()} for path, data in self.payloads.items()],
|
||||
}
|
||||
self.manifest = self.root / "SOURCE-ARCHIVE-MANIFEST.json"
|
||||
|
||||
def write_archive(self):
|
||||
with tarfile.open(self.archive, "w:gz") as archive:
|
||||
for path, data in self.payloads.items():
|
||||
info = tarfile.TarInfo("FrameBridge-0.3.4/" + path)
|
||||
info.size = len(data)
|
||||
archive.addfile(info, io.BytesIO(data))
|
||||
|
||||
def check(self, profile="debian13-amd64-py313", version="0.3.4"):
|
||||
self.manifest.write_text(json.dumps(self.data))
|
||||
return release_source(self.manifest, version, profile, {"source/module.py": self.file}, self.vendor)
|
||||
|
||||
def test_release_binds_archive_source_and_both_vendor_abis(self):
|
||||
for profile in ("debian13-amd64-py313", "ubuntu24.04-amd64-py312", "mint22-amd64-py312"):
|
||||
self.assertEqual(self.check(profile)["sha256"], self.data["sha256"])
|
||||
|
||||
def test_source_changed_after_archive_is_rejected(self):
|
||||
self.file.write_text("# later edit\n")
|
||||
with self.assertRaisesRegex(RuntimeError, "Package source differs"):
|
||||
self.check()
|
||||
|
||||
def test_archive_tamper_is_rejected(self):
|
||||
with self.archive.open("ab") as stream:
|
||||
stream.write(b"altered")
|
||||
with self.assertRaisesRegex(RuntimeError, "archive hash or size"):
|
||||
self.check()
|
||||
|
||||
def test_changed_manifest_cannot_relabel_old_archive_contents(self):
|
||||
self.file.write_text("# later edit\n")
|
||||
self.data["files"][0]["sha256"] = hashlib.sha256(self.file.read_bytes()).hexdigest()
|
||||
with self.assertRaisesRegex(RuntimeError, "archive content differs"):
|
||||
self.check()
|
||||
|
||||
def test_relabelled_alternate_vendor_bytes_are_rejected_even_by_debian_build(self):
|
||||
self.payloads[self.vendor_paths["cp312"] + "/module.py"] = b"# different vendor bytes\n"
|
||||
self.write_archive()
|
||||
self.data.update(bytes=self.archive.stat().st_size, sha256=hashlib.sha256(self.archive.read_bytes()).hexdigest())
|
||||
self.data["files"] = [{"path": path, "sha256": hashlib.sha256(data).hexdigest()} for path, data in self.payloads.items()]
|
||||
with self.assertRaisesRegex(RuntimeError, "Archived vendor bytes differ"):
|
||||
self.check()
|
||||
|
||||
def test_unsafe_archive_member_is_rejected_without_extracting(self):
|
||||
self.payloads["../escape"] = b"unwanted path"
|
||||
self.write_archive()
|
||||
self.data.update(bytes=self.archive.stat().st_size, sha256=hashlib.sha256(self.archive.read_bytes()).hexdigest())
|
||||
self.data["files"].append({"path": "../escape", "sha256": hashlib.sha256(b"unwanted path").hexdigest()})
|
||||
with self.assertRaisesRegex(RuntimeError, "Unsafe release source archive path"):
|
||||
self.check()
|
||||
|
||||
def test_release_requires_cp312_corresponding_source(self):
|
||||
del self.data["vendor_inputs"]["vendors"]["cp312"]
|
||||
with self.assertRaisesRegex(RuntimeError, "cp312 and cp313"):
|
||||
self.check()
|
||||
|
||||
def test_vendor_input_cannot_differ_from_corresponding_source(self):
|
||||
self.data["vendor_inputs"]["vendors"]["cp312"]["vendor_sha256"] = "b" * 64
|
||||
with self.assertRaisesRegex(RuntimeError, "vendor input differs"):
|
||||
self.check("mint22-amd64-py312")
|
||||
|
||||
def test_candidate_version_and_experimental_profile_are_not_public_release(self):
|
||||
for profile, version in (("lmde7-amd64-py313", "0.3.4"), ("debian13-amd64-py313", "0.3.4~dev.1")):
|
||||
with self.assertRaisesRegex(RuntimeError, "stable version and an official"):
|
||||
self.check(profile, version)
|
||||
|
||||
def test_public_metadata_names_source_without_claiming_signature_or_vm_qa(self):
|
||||
docs = self.root / "docs"
|
||||
docs.mkdir()
|
||||
identity = self.check()
|
||||
with mock.patch.object(build_expanded, "PUBLIC_RELEASE", True), \
|
||||
mock.patch.object(build_expanded, "SOURCE_ARCHIVE", identity), \
|
||||
mock.patch.object(build_expanded, "VERSION", "0.3.4"):
|
||||
build_expanded.install_legal_material(docs)
|
||||
result = json.loads((docs / "COMMUNITY-RELEASE-STATUS.json").read_text())
|
||||
self.assertEqual(result["status"], "PUBLIC_RELEASE_BUILD_ASSEMBLED")
|
||||
self.assertEqual(result["source_archive"], identity)
|
||||
self.assertEqual(result["signature_status"], "EXTERNAL_RELEASE_RECORD")
|
||||
self.assertEqual(result["vm_lifecycle_validation"], "NOT_ASSERTED_BY_BUILDER")
|
||||
self.assertNotIn("compatibility candidate", (docs / "copyright").read_text())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user