From 04d62d92c46d2f2932c000a3aadfeb747d1b8fd6 Mon Sep 17 00:00:00 2001 From: lucarlig Date: Mon, 5 Oct 2026 12:24:51 +0100 Subject: [PATCH] fix: bind release builds to the workflow commit Signed-off-by: lucarlig --- .github/workflows/release-python-package.yaml | 30 +++++++++---------- .../release-rust-python-package.yaml | 30 +++++++++---------- DEVELOPING.md | 7 +++++ 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/.github/workflows/release-python-package.yaml b/.github/workflows/release-python-package.yaml index f5f92ae..354f74e 100644 --- a/.github/workflows/release-python-package.yaml +++ b/.github/workflows/release-python-package.yaml @@ -7,7 +7,7 @@ on: workflow_call: inputs: tag: - description: "Release tag in the form -v" + description: "Release tag -v at the workflow commit" required: true type: string repository: @@ -22,7 +22,7 @@ on: workflow_dispatch: inputs: tag: - description: "Release tag in the form -v" + description: "Release tag -v at the workflow commit; dispatch on this tag" required: true type: string repository: @@ -51,11 +51,12 @@ jobs: plugin_path: ${{ steps.resolve.outputs.plugin_path }} publish_env: ${{ steps.resolve.outputs.publish_env }} publish_enabled: ${{ steps.resolve.outputs.publish_enabled }} - checkout_ref: ${{ steps.resolve.outputs.checkout_ref }} tag_on_main: ${{ steps.resolve.outputs.tag_on_main }} skip: ${{ steps.resolve.outputs.skip }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -76,14 +77,16 @@ jobs: if [[ -n "${TAG_INPUT}" ]]; then tag="${TAG_INPUT}" repository="${REPOSITORY_INPUT}" + git check-ref-format "refs/tags/${tag}" if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then git fetch --force origin "refs/tags/${tag}:refs/tags/${tag}" - git show-ref --verify --quiet "refs/tags/${tag}" - checkout_ref="refs/tags/${tag}" - tag_ref="refs/tags/${tag}" + tag_sha="$(git rev-parse --verify "refs/tags/${tag}^{commit}")" + if [[ "${tag_sha}" != "${GITHUB_SHA}" ]]; then + echo "Release tag ${tag} does not match workflow commit ${GITHUB_SHA}; dispatch on the release tag" >&2 + exit 1 + fi elif [[ "${GITHUB_EVENT_NAME}" == "pull_request" && "${PUBLISH_ENABLED}" == "false" ]]; then - checkout_ref="${GITHUB_SHA}" - tag_ref="${GITHUB_SHA}" + echo "Validating unreleased tag ${tag} at PR commit ${GITHUB_SHA}" else echo "Release tag ${tag} does not exist" >&2 exit 1 @@ -91,11 +94,9 @@ jobs: else tag="${GITHUB_REF_NAME}" repository="pypi" - checkout_ref="${GITHUB_REF}" - tag_ref="${GITHUB_REF}" fi - if git merge-base --is-ancestor "${tag_ref}" "refs/remotes/origin/main"; then + if git merge-base --is-ancestor "${GITHUB_SHA}" "refs/remotes/origin/main"; then tag_on_main=true else tag_on_main=false @@ -114,7 +115,6 @@ jobs: { echo "plugin=${plugin}" echo "plugin_path=${plugin_path}" - echo "checkout_ref=${checkout_ref}" echo "tag_on_main=${tag_on_main}" if [[ "${skip}" == "true" ]]; then echo "skip=true" @@ -143,7 +143,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ needs.resolve.outputs.checkout_ref }} + ref: ${{ github.sha }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -173,7 +173,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ needs.resolve.outputs.checkout_ref }} + ref: ${{ github.sha }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -224,7 +224,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ needs.resolve.outputs.checkout_ref }} + ref: ${{ github.sha }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: diff --git a/.github/workflows/release-rust-python-package.yaml b/.github/workflows/release-rust-python-package.yaml index cc9a768..308f384 100644 --- a/.github/workflows/release-rust-python-package.yaml +++ b/.github/workflows/release-rust-python-package.yaml @@ -7,7 +7,7 @@ on: workflow_call: inputs: tag: - description: "Release tag in the form -v" + description: "Release tag -v at the workflow commit" required: true type: string repository: @@ -22,7 +22,7 @@ on: workflow_dispatch: inputs: tag: - description: "Release tag in the form -v" + description: "Release tag -v at the workflow commit; dispatch on this tag" required: true type: string repository: @@ -51,11 +51,12 @@ jobs: wheel_matrix: ${{ steps.resolve.outputs.wheel_matrix }} publish_env: ${{ steps.resolve.outputs.publish_env }} publish_enabled: ${{ steps.resolve.outputs.publish_enabled }} - checkout_ref: ${{ steps.resolve.outputs.checkout_ref }} tag_on_main: ${{ steps.resolve.outputs.tag_on_main }} skip: ${{ steps.resolve.outputs.skip }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.sha }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -76,14 +77,16 @@ jobs: if [[ -n "${TAG_INPUT}" ]]; then tag="${TAG_INPUT}" repository="${REPOSITORY_INPUT}" + git check-ref-format "refs/tags/${tag}" if git ls-remote --exit-code --tags origin "refs/tags/${tag}" >/dev/null 2>&1; then git fetch --force origin "refs/tags/${tag}:refs/tags/${tag}" - git show-ref --verify --quiet "refs/tags/${tag}" - checkout_ref="refs/tags/${tag}" - tag_ref="refs/tags/${tag}" + tag_sha="$(git rev-parse --verify "refs/tags/${tag}^{commit}")" + if [[ "${tag_sha}" != "${GITHUB_SHA}" ]]; then + echo "Release tag ${tag} does not match workflow commit ${GITHUB_SHA}; dispatch on the release tag" >&2 + exit 1 + fi elif [[ "${GITHUB_EVENT_NAME}" == "pull_request" && "${PUBLISH_ENABLED}" == "false" ]]; then - checkout_ref="${GITHUB_SHA}" - tag_ref="${GITHUB_SHA}" + echo "Validating unreleased tag ${tag} at PR commit ${GITHUB_SHA}" else echo "Release tag ${tag} does not exist" >&2 exit 1 @@ -91,11 +94,9 @@ jobs: else tag="${GITHUB_REF_NAME}" repository="pypi" - checkout_ref="${GITHUB_REF}" - tag_ref="${GITHUB_REF}" fi - if git merge-base --is-ancestor "${tag_ref}" "refs/remotes/origin/main"; then + if git merge-base --is-ancestor "${GITHUB_SHA}" "refs/remotes/origin/main"; then tag_on_main=true else tag_on_main=false @@ -120,7 +121,6 @@ jobs: echo "plugin=${plugin}" echo "plugin_path=${plugin_path}" echo "wheel_matrix=${wheel_matrix}" - echo "checkout_ref=${checkout_ref}" echo "tag_on_main=${tag_on_main}" if [[ "${skip}" == "true" ]]; then echo "skip=true" @@ -149,7 +149,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ needs.resolve.outputs.checkout_ref }} + ref: ${{ github.sha }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: @@ -178,7 +178,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ needs.resolve.outputs.checkout_ref }} + ref: ${{ github.sha }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 if: ${{ matrix.runner != 'ubuntu-24.04-s390x' && matrix.runner != 'ubuntu-24.04-ppc64le' }} @@ -254,7 +254,7 @@ jobs: steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ needs.resolve.outputs.checkout_ref }} + ref: ${{ github.sha }} - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: diff --git a/DEVELOPING.md b/DEVELOPING.md index 13727f6..77d8fb3 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -237,5 +237,12 @@ The matching workflow validates metadata and versions, builds and tests the plugin's artifacts, and publishes only that plugin. PyPI publishing is allowed only for release tags that point at `main`. +Every release job checks out the immutable workflow commit (`github.sha`). +A supplied release tag must resolve to that same commit; it cannot select +different code to execute within the workflow's cache scope. For a manual +release, dispatch on the release tag (`gh workflow run --ref +-f tag= ...`), as the CI workflows already do. A nonexistent tag is allowed +only for PR artifact validation with publishing disabled. + Dependency refresh work is separate from the release process. Track broader dependency or ContextForge updates outside a plugin release PR.