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
39 changes: 36 additions & 3 deletions .github/ci/ci-tests/test_package_release_workflow.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,24 @@ def test_workflow_selects_an_immutable_release_source():
assert 'git checkout "$SOURCE_COMMIT" -- .resolver-plugins/upstream.json Mk dns/bind' in workflow


def test_package_affecting_master_pushes_publish_the_active_series():
workflow = workflow_text()

assert 'push:\n branches: [master]' in workflow
for path in (
"'.github/ci/**'",
"'.github/workflows/package-release.yml'",
"'.resolver-plugins/**'",
"'docs/package-repository/resolver-plugins.pub'",
"'dns/bind/**'",
"'Mk/**'",
):
assert path in workflow
assert "group: package-release-${{ inputs.series || '26.7' }}" in workflow
assert "INPUT_MODE: ${{ github.event_name == 'push' && 'production' || inputs.mode }}" in workflow
assert "INPUT_SERIES: ${{ github.event_name == 'push' && '26.7' || inputs.series }}" in workflow


def test_production_runs_only_from_the_master_control_plane():
workflow = workflow_text()
select = workflow.split(' select:', 1)[1].split(' profile:', 1)[0]
Expand All @@ -43,7 +61,7 @@ def test_production_runs_only_from_the_master_control_plane():
assert 'ref: ${{ needs.select.outputs.control_ref }}' in profile
for job in (test, bind, build):
assert 'ref: ${{ needs.profile.outputs.control_commit }}' in job
assert 'group: package-release-${{ inputs.series }}' in workflow
assert "group: package-release-${{ inputs.series || '26.7' }}" in workflow
assert 'cancel-in-progress: false' in workflow


Expand Down Expand Up @@ -99,7 +117,7 @@ def test_production_signing_and_publication_are_separate_from_builds():
assert 'python3 .github/ci/release_channel.py stage-channel' in workflow
assert 'python3 .github/ci/release_channel.py validate-bind-provenance' in workflow
assert '--profile .resolver-plugins/bind920.json' in workflow
assert "--series '${{ needs.select.outputs.series }}'" in workflow
assert '--series "$SERIES"' in workflow
assert "--freebsd-release '${{ needs.profile.outputs.freebsd_release }}'" in workflow
assert 'python3 .github/ci/release_channel.py publish-channels' in workflow
assert 'permissions:\n contents: write' in workflow
Expand All @@ -121,9 +139,16 @@ def test_signer_uses_master_control_plane_and_self_contained_channel_layout():
assert 'cmp -s docs/package-repository/resolver-plugins.pub "$output/resolver-plugins.pub"' in signer
assert 'trusted-upstream.json' in signer
assert 'validate-build-metadata' in signer
assert signer.count('--target-pkg-metadata .resolver-plugins/target-pkg.json') == 3
assert signer.count('--target-pkg-metadata .resolver-plugins/target-pkg.json') == 4
assert 'id: reuse-snapshot' in signer
assert 'reuse-snapshot --repository resolver-plugins/repository' in signer
assert '--provenance "$output/bind920-provenance.json"' in signer
reuse = signer.split('- name: Reuse existing immutable snapshot', 1)[1].split(
'- name: Sign package repository', 1
)[0]
reuse_command = 'release_channel.py reuse-snapshot'
assert reuse.index('validate-bind-provenance') < reuse.index(reuse_command)
assert reuse.index('validate-build-metadata') < reuse.index(reuse_command)
assert "if: steps.reuse-snapshot.outputs.reused != 'true'" in signer
assert '--public-key docs/package-repository/resolver-plugins.pub' in signer
assert 'repository/bind920' not in signer
Expand Down Expand Up @@ -311,11 +336,19 @@ def test_source_release_contains_only_plugin_and_build_metadata():
assert 'gh release view "$tag"' not in source_release
assert 'gh release create "$tag"' not in source_release
assert 'set -- "$output"/os-bind-rp-*.pkg' in source_release
assert 'source-release-tag "$SERIES" "$version" --provenance "$output/bind920-provenance.json"' in source_release
assert 'cp "$1" "$output/build-metadata.txt" "$source_output/"' in source_release
assert 'bind920-*.pkg' not in source_release
assert 'os-bind-rp-build-production-' not in source_release


def test_immutable_package_snapshot_is_scoped_to_the_bind_build():
workflow = workflow_text()
publisher = workflow.split(' publish:', 1)[1].split(' verify:', 1)[0]

assert 'snapshot-tag "$SERIES" "$version" --provenance "$root/current/bind920-provenance.json"' in publisher


def test_all_freebsd_install_gates_pin_pkg_and_test_the_official_replacement_path():
workflow = workflow_text()
verifiers = {
Expand Down
150 changes: 142 additions & 8 deletions .github/ci/ci-tests/test_release_channel_archive.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,26 @@
SPEC.loader.exec_module(release_channel)


def target_creator_record(digest: str = "a" * 64) -> dict[str, str]:
return {
"abi": "FreeBSD:15:amd64",
"filename": "pkg-2.3.1_1.pkg",
"name": "pkg",
"origin": "ports-mgmt/pkg",
"pkg_static_sha256": digest,
"sha256": digest,
"version": "2.3.1_1",
}


def bind_provenance_record(fingerprint: str = "f" * 64) -> dict[str, object]:
return {
"architecture": "x86_64",
"fingerprint": fingerprint,
"freebsd_release": "15.1",
}


class ChannelTagTest(unittest.TestCase):
def test_series_abi_path_uses_exact_freebsd_amd64_package_abi_and_series(self) -> None:
"""A package ABI and OPNsense series select one static repository path."""
Expand Down Expand Up @@ -51,25 +71,30 @@ def test_package_release_title_rejects_non_channel_tags(self) -> None:
with self.assertRaisesRegex(ValueError, "invalid package release tag"):
release_channel.package_release_title(tag)

def test_source_release_tag_identifies_the_series_and_plugin_version(self) -> None:
def test_source_release_tag_identifies_the_series_plugin_and_bind_build(self) -> None:
fingerprint = "f" * 64
self.assertEqual(
"os-bind-rp-26.7-1.36_7", release_channel.source_release_tag("26.7", "1.36_7")
f"os-bind-rp-26.7-1.36_7-bind-{fingerprint}",
release_channel.source_release_tag("26.7", "1.36_7", fingerprint),
)

def test_channel_tags_are_series_scoped(self) -> None:
"""Current and immutable snapshot channels must never share a tag."""
fingerprint = "f" * 64
self.assertEqual("pkg-26.7", release_channel.channel_tag("26.7"))
self.assertEqual(
"pkg-26.7-os-bind-rp-1.36_2",
release_channel.snapshot_channel_tag("26.7", "1.36_2"),
f"pkg-26.7-os-bind-rp-1.36_2-bind-{fingerprint}",
release_channel.snapshot_channel_tag("26.7", "1.36_2", fingerprint),
)

def test_channel_tags_reject_invalid_series(self) -> None:
"""Channel names remain constrained to the supported series form."""
with self.assertRaisesRegex(ValueError, "invalid series"):
release_channel.channel_tag("26.7/archive")
with self.assertRaisesRegex(ValueError, "invalid package version"):
release_channel.snapshot_channel_tag("26.7", "1.36/2")
release_channel.snapshot_channel_tag("26.7", "1.36/2", "f" * 64)
with self.assertRaisesRegex(ValueError, "invalid BIND fingerprint"):
release_channel.snapshot_channel_tag("26.7", "1.36_2", "not-a-fingerprint")


class GitHubCliTest(unittest.TestCase):
Expand Down Expand Up @@ -805,6 +830,8 @@ def test_existing_snapshot_is_materialized_for_an_exact_release_retry(self) -> N
(remote / "channel.json").write_text(
json.dumps(
{
"bind": bind_provenance_record(),
"package_creator": target_creator_record(),
"series": "26.7",
"plugin_version": "1.36_2",
"source_commit": "a" * 40,
Expand All @@ -816,12 +843,18 @@ def test_existing_snapshot_is_materialized_for_an_exact_release_retry(self) -> N
public_key = root / "resolver-plugins.pub"
public_key.write_bytes(b"trusted key")
(remote / public_key.name).write_bytes(public_key.read_bytes())
fingerprint = bind_provenance_record()["fingerprint"]
snapshot = release_channel.ReleaseSnapshot(
"pkg-26.7-os-bind-rp-1.36_2", True, remote, root / "manifest.json"
f"pkg-26.7-os-bind-rp-1.36_2-bind-{fingerprint}",
True,
remote,
root / "manifest.json",
)

with (
patch.object(release_channel, "snapshot_release", return_value=snapshot),
patch.object(
release_channel, "snapshot_release", return_value=snapshot
) as snapshot_release,
patch.object(release_channel, "validate_channel_directory") as validate,
):
reused = release_channel.materialize_existing_snapshot(
Expand All @@ -831,9 +864,18 @@ def test_existing_snapshot_is_materialized_for_an_exact_release_retry(self) -> N
"a" * 40,
root / "repository",
public_key,
target_creator_record(),
bind_provenance_record(),
)

self.assertTrue(reused)
self.assertEqual(
(
"resolver-plugins/repository",
f"pkg-26.7-os-bind-rp-1.36_2-bind-{fingerprint}",
),
snapshot_release.call_args.args[:2],
)
validate.assert_called_once_with(remote)
for channel in ("current", "snapshot"):
self.assertEqual(
Expand All @@ -860,6 +902,8 @@ def test_absent_snapshot_leaves_signing_output_unmodified(self) -> None:
"b" * 40,
root / "repository",
public_key,
target_creator_record(),
bind_provenance_record(),
)

self.assertFalse(reused)
Expand All @@ -873,6 +917,8 @@ def test_snapshot_reuse_rejects_different_release_source(self) -> None:
(remote / "channel.json").write_text(
json.dumps(
{
"bind": bind_provenance_record(),
"package_creator": target_creator_record(),
"series": "26.7",
"plugin_version": "1.36_2",
"source_commit": "a" * 40,
Expand All @@ -898,6 +944,86 @@ def test_snapshot_reuse_rejects_different_release_source(self) -> None:
"b" * 40,
root / "repository",
public_key,
target_creator_record(),
bind_provenance_record(),
)

def test_snapshot_reuse_rejects_different_bind_provenance(self) -> None:
with tempfile.TemporaryDirectory() as temporary_directory:
root = Path(temporary_directory)
remote = root / "remote"
remote.mkdir()
(remote / "channel.json").write_text(
json.dumps(
{
"bind": bind_provenance_record("b" * 64),
"package_creator": target_creator_record(),
"series": "26.7",
"plugin_version": "1.36_2",
"source_commit": "a" * 40,
}
),
encoding="utf-8",
)
public_key = root / "resolver-plugins.pub"
public_key.write_bytes(b"trusted key")
(remote / public_key.name).write_bytes(public_key.read_bytes())
snapshot = release_channel.ReleaseSnapshot(
"pkg-26.7-os-bind-rp-1.36_2", True, remote, root / "manifest.json"
)
with (
patch.object(release_channel, "snapshot_release", return_value=snapshot),
patch.object(release_channel, "validate_channel_directory"),
):
with self.assertRaisesRegex(ValueError, "does not match requested release"):
release_channel.materialize_existing_snapshot(
"resolver-plugins/repository",
"26.7",
"1.36_2",
"a" * 40,
root / "repository",
public_key,
target_creator_record(),
bind_provenance_record("c" * 64),
)

def test_snapshot_reuse_rejects_different_target_pkg_creator(self) -> None:
with tempfile.TemporaryDirectory() as temporary_directory:
root = Path(temporary_directory)
remote = root / "remote"
remote.mkdir()
(remote / "channel.json").write_text(
json.dumps(
{
"bind": bind_provenance_record(),
"package_creator": target_creator_record("b" * 64),
"series": "26.7",
"plugin_version": "1.36_2",
"source_commit": "a" * 40,
}
),
encoding="utf-8",
)
public_key = root / "resolver-plugins.pub"
public_key.write_bytes(b"trusted key")
(remote / public_key.name).write_bytes(public_key.read_bytes())
snapshot = release_channel.ReleaseSnapshot(
"pkg-26.7-os-bind-rp-1.36_2", True, remote, root / "manifest.json"
)
with (
patch.object(release_channel, "snapshot_release", return_value=snapshot),
patch.object(release_channel, "validate_channel_directory"),
):
with self.assertRaisesRegex(ValueError, "does not match requested release"):
release_channel.materialize_existing_snapshot(
"resolver-plugins/repository",
"26.7",
"1.36_2",
"a" * 40,
root / "repository",
public_key,
target_creator_record("c" * 64),
bind_provenance_record(),
)

def test_recovery_channel_rejects_an_audit_checksum_mismatch(self) -> None:
Expand Down Expand Up @@ -1315,8 +1441,16 @@ def test_repository_latest_is_the_current_channel_for_the_highest_series(self) -

def test_snapshot_pruning_keeps_the_newest_five_immutable_tags(self) -> None:
"""Only a successful promotion may remove the sixth-oldest snapshot."""
fingerprint = "f" * 64
releases = [
{"tag_name": f"pkg-26.7-os-bind-rp-1.36_{number}", "created_at": f"2026-01-0{number}T00:00:00Z"}
{
"tag_name": (
f"pkg-26.7-os-bind-rp-1.36_{number}-bind-{fingerprint}"
if number % 2 == 0
else f"pkg-26.7-os-bind-rp-1.36_{number}"
),
"created_at": f"2026-01-0{number}T00:00:00Z",
}
for number in range(1, 7)
]
# `gh api --paginate --slurp` returns one JSON array per fetched page.
Expand Down
Loading
Loading