Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .github/ci/bind920_profile.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
SERIES_PATTERN = re.compile(r"[0-9]+\.[0-9]+")
FREEBSD_RELEASE_PATTERN = re.compile(r"[0-9]+\.[0-9]+")
ARCHITECTURE_PATTERN = re.compile(r"[a-z0-9_]+")
PROVENANCE_SCHEMA = 2
PROVENANCE_SCHEMA = 3
BUILD_RECIPE_PATH = Path(__file__).with_name("build-bind920.sh")
PACKAGE_CREATOR_FIELDS = {
"name",
"version",
Expand Down Expand Up @@ -102,6 +103,14 @@ def validate_package_creator(package_creator: object) -> dict[str, str]:
return package_creator


def build_recipe_sha256() -> str:
"""Identify the local build policy that produces the reusable BIND pair."""
try:
return hashlib.sha256(BUILD_RECIPE_PATH.read_bytes()).hexdigest()
except OSError as error:
raise ValueError(f"cannot read BIND build recipe: {error}") from error


def compatibility_fingerprint(
profile: object,
series: str,
Expand All @@ -124,6 +133,7 @@ def compatibility_fingerprint(
"freebsd_release": freebsd_release,
"architecture": architecture,
"bind_profile": profile,
"build_recipe_sha256": build_recipe_sha256(),
"package_creator": package_creator,
}
encoded = json.dumps(inputs, sort_keys=True, separators=(",", ":")).encode("utf-8")
Expand Down Expand Up @@ -167,6 +177,7 @@ def build_provenance(
"series": series,
"freebsd_release": freebsd_release,
"architecture": architecture,
"build_recipe_sha256": build_recipe_sha256(),
"package_creator": package_creator,
"packages": validated_packages,
}
Expand Down
19 changes: 19 additions & 0 deletions .github/ci/ci-tests/test_bind920_reuse.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import tempfile
import unittest
from pathlib import Path
from unittest.mock import patch


MODULE_PATH = Path(__file__).resolve().parents[1] / "bind920_profile.py"
Expand Down Expand Up @@ -67,13 +68,31 @@ def test_fingerprint_rejects_different_compatibility_inputs(self) -> None:
self.assertNotEqual(baseline, bind920_profile.compatibility_fingerprint(changed_profile, "26.1", "14.3", "x86_64", PACKAGE_CREATOR))
self.assertNotEqual(baseline, bind920_profile.compatibility_fingerprint(PROFILE, "26.1", "14.3", "x86_64", dict(PACKAGE_CREATOR, sha256="c" * 64)))

def test_fingerprint_changes_when_the_bind_build_recipe_changes(self) -> None:
"""A build-policy change must force fresh BIND package archives."""
with tempfile.TemporaryDirectory() as temporary_directory:
recipe = Path(temporary_directory) / "build-bind920.sh"
recipe.write_text("pkg install lmdb\n", encoding="utf-8")
with patch.object(bind920_profile, "BUILD_RECIPE_PATH", recipe):
baseline = bind920_profile.compatibility_fingerprint(
PROFILE, "26.1", "14.3", "x86_64", PACKAGE_CREATOR
)
recipe.write_text("pkg install lmdb0\n", encoding="utf-8")
corrected = bind920_profile.compatibility_fingerprint(
PROFILE, "26.1", "14.3", "x86_64", PACKAGE_CREATOR
)

self.assertNotEqual(baseline, corrected)

def test_provenance_requires_exact_bind_package_identities(self) -> None:
"""A cache candidate must identify both BIND package archives exactly."""
provenance = bind920_profile.build_provenance(
PROFILE, "26.1", "14.3", "x86_64", PACKAGE_CREATOR, PACKAGES
)
self.assertEqual("dns/bind920", provenance["packages"]["bind920"]["origin"])
self.assertEqual(PACKAGE_CREATOR, provenance["package_creator"])
self.assertEqual(3, provenance["schema"])
self.assertRegex(provenance["build_recipe_sha256"], r"^[0-9a-f]{64}$")
invalid = dict(PACKAGES)
invalid["bind920"] = dict(PACKAGES["bind920"], origin="dns/bind918")
with self.assertRaisesRegex(ValueError, "bind920 package"):
Expand Down
17 changes: 16 additions & 1 deletion .github/ci/ci-tests/test_reuse_bind920.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,12 @@
"pkg_static_sha256": "b" * 64,
}
PROVENANCE = {
"schema": 2,
"schema": reuse_bind920.bind920_profile.PROVENANCE_SCHEMA,
"fingerprint": "",
"series": "26.1",
"freebsd_release": "14.3",
"architecture": "x86_64",
"build_recipe_sha256": reuse_bind920.bind920_profile.build_recipe_sha256(),
"package_creator": PACKAGE_CREATOR,
"packages": {
"bind-tools": {
Expand Down Expand Up @@ -118,6 +119,20 @@ def test_old_or_different_creator_provenance_is_a_cache_miss(self) -> None:
changed, PROFILE, "26.1", "14.3", "x86_64", PACKAGE_CREATOR
)

def test_schema_two_provenance_is_a_cache_miss_after_build_recipe_versioning(self) -> None:
legacy = dict(
PROVENANCE,
schema=2,
fingerprint=reuse_bind920.bind920_profile.compatibility_fingerprint(
PROFILE, "26.1", "14.3", "x86_64", PACKAGE_CREATOR
),
)

with self.assertRaises(reuse_bind920.CacheMiss):
reuse_bind920.select_candidate(
legacy, PROFILE, "26.1", "14.3", "x86_64", PACKAGE_CREATOR
)

def test_invalid_package_identity_is_rejected(self) -> None:
"""Malformed matching metadata must not silently become a cache miss."""
provenance = dict(PROVENANCE, packages=dict(PROVENANCE["packages"]))
Expand Down
9 changes: 4 additions & 5 deletions .github/ci/reuse_bind920.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
PACKAGE_FIELDS = {"name", "version", "origin", "filename"}
PROVENANCE_FIELDS = {
"schema", "fingerprint", "series", "freebsd_release", "architecture",
"package_creator", "packages",
"build_recipe_sha256", "package_creator", "packages",
}


Expand All @@ -45,10 +45,9 @@ def select_candidate(
"""Validate and select a compatible BIND package pair from provenance."""
if not isinstance(provenance, dict):
raise ValueError("BIND provenance has an invalid schema")
if (
provenance.get("schema") != bind920_profile.PROVENANCE_SCHEMA
or provenance.get("package_creator") != package_creator
):
if provenance.get("schema") != bind920_profile.PROVENANCE_SCHEMA:
raise CacheMiss("stable BIND provenance schema differs")
if provenance.get("package_creator") != package_creator:
raise CacheMiss("stable BIND package creator differs")
if not isinstance(provenance, dict) or set(provenance) != PROVENANCE_FIELDS:
raise ValueError("BIND provenance has an invalid schema")
Expand Down
Loading