From 61463a24cbfb6c3e749fa7e47e279a45101a7399 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Tue, 4 Aug 2026 16:43:54 +0200 Subject: [PATCH] Bind runtime releases to protected source tags [skip ci] --- .gitea/workflows/runtime-distribution.yml | 13 +++++++++++-- docs/PACKAGE_REGISTRY_RELEASES.md | 6 ++++++ tests/test_runtime_distribution_build.py | 18 ++++++++++++++++-- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/.gitea/workflows/runtime-distribution.yml b/.gitea/workflows/runtime-distribution.yml index e549ef8..4e96aa4 100644 --- a/.gitea/workflows/runtime-distribution.yml +++ b/.gitea/workflows/runtime-distribution.yml @@ -92,6 +92,15 @@ jobs: if image_pattern.fullmatch(os.environ[name]) is None: raise SystemExit(f"{name} must be an exact sha256 image reference") PY + - name: Resolve immutable release source + working-directory: govoplan + env: + VERSION: ${{ inputs.version }} + run: | + git fetch --force --no-tags origin "refs/tags/v$VERSION:refs/tags/v$VERSION" + mkdir -p runtime-output + git rev-parse "v$VERSION^{commit}" > runtime-output/release-source-commit + grep -Eq '^[0-9a-f]{40}$' runtime-output/release-source-commit - name: Use HTTPS for GovOPlaN repositories run: | git config --global --add url."https://git.add-ideas.de/GovOPlaN/govoplan".insteadOf "git@git.add-ideas.de:GovOPlaN/govoplan" @@ -255,7 +264,6 @@ jobs: working-directory: govoplan env: VERSION: ${{ inputs.version }} - SOURCE_COMMIT: ${{ gitea.sha }} SIGNING_KEY: ${{ secrets.RUNTIME_DISTRIBUTION_SIGNING_KEY }} SIGNING_KEY_ID: ${{ secrets.RUNTIME_DISTRIBUTION_SIGNING_KEY_ID }} TRUSTED_KEYRING: ${{ secrets.RUNTIME_DISTRIBUTION_KEYRING }} @@ -266,6 +274,7 @@ jobs: GARAGE_IMAGE: ${{ inputs.garage_image }} TEST_MAIL_IMAGE: ${{ inputs.test_mail_image }} run: | + SOURCE_COMMIT="$(cat runtime-output/release-source-commit)" test -n "$SIGNING_KEY" test -n "$SIGNING_KEY_ID" test -n "$TRUSTED_KEYRING" @@ -363,9 +372,9 @@ jobs: working-directory: govoplan env: VERSION: ${{ inputs.version }} - SOURCE_COMMIT: ${{ gitea.sha }} GITEA_RELEASE_TOKEN: ${{ secrets.GOVOPLAN_RELEASE_TOKEN }} run: | + SOURCE_COMMIT="$(cat runtime-output/release-source-commit)" python tools/release/publish-runtime-release.py \ --tag "v$VERSION" \ --target-commit "$SOURCE_COMMIT" \ diff --git a/docs/PACKAGE_REGISTRY_RELEASES.md b/docs/PACKAGE_REGISTRY_RELEASES.md index 83dd9e3..863c49f 100644 --- a/docs/PACKAGE_REGISTRY_RELEASES.md +++ b/docs/PACKAGE_REGISTRY_RELEASES.md @@ -155,6 +155,12 @@ installs module WebUI tarballs only after matching them to the lock. It publishe the package set, package lock, and hash-locked requirements as release assets. The WebUI installer receives the absolute runtime-build interpreter path so its directory changes cannot escape the isolated release environment. +Gitea 1.24 dispatches this workflow from a branch, but that branch is only the +workflow implementation. The job fetches and peels the protected `v` +tag explicitly, then binds both the signed distribution source and the Gitea +release assets to that exact commit. A post-tag workflow repair can therefore +retry publication without relabelling the later branch commit as released +source. The package-lock SHA-256 is part of the signed distribution manifest. Runtime finalization also requires the lock's package versions and hashes to match the wheel composition embedded in the images. OCI assembly remains network-free diff --git a/tests/test_runtime_distribution_build.py b/tests/test_runtime_distribution_build.py index 3db50bf..8207d0f 100644 --- a/tests/test_runtime_distribution_build.py +++ b/tests/test_runtime_distribution_build.py @@ -163,7 +163,7 @@ class RuntimeDistributionBuildTests(unittest.TestCase): ) self.assertNotIn(".platforms[\\\"linux/amd64\\\"]", workflow) - def test_workflow_binds_the_release_tag_to_the_workflow_commit(self) -> None: + def test_workflow_binds_distribution_to_the_peeled_release_tag(self) -> None: workflow = (ROOT / ".gitea/workflows/runtime-distribution.yml").read_text( encoding="utf-8" ) @@ -171,7 +171,21 @@ class RuntimeDistributionBuildTests(unittest.TestCase): encoding="utf-8" ) - self.assertIn("SOURCE_COMMIT: ${{ gitea.sha }}", workflow) + self.assertIn( + 'git fetch --force --no-tags origin "refs/tags/v$VERSION:refs/tags/v$VERSION"', + workflow, + ) + self.assertIn( + 'git rev-parse "v$VERSION^{commit}" > runtime-output/release-source-commit', + workflow, + ) + self.assertEqual( + 2, + workflow.count( + 'SOURCE_COMMIT="$(cat runtime-output/release-source-commit)"' + ), + ) + self.assertNotIn("SOURCE_COMMIT: ${{ gitea.sha }}", workflow) self.assertIn('--target-commit "$SOURCE_COMMIT"', workflow) self.assertIn('"target_commitish": target_commit', publisher) self.assertIn("self._resolve_commit(tag) != target_commit", publisher)