Skip to content

Recover immutable release publication #1

Recover immutable release publication

Recover immutable release publication #1

name: Recover immutable release publication
on:
workflow_dispatch:
inputs:
release-tag:
description: Exact immutable GitHub release tag
required: true
type: string
release-sha:
description: Exact commit resolved by the release tag
required: true
type: string
permissions:
contents: read
concurrency:
group: release-recovery
cancel-in-progress: false
jobs:
verify-recovery:
name: Verify the authorized immutable release recovery
if: >-
github.run_attempt == 1 &&
github.ref == format('refs/heads/{0}', github.event.repository.default_branch) &&
vars.RELEASE_RECOVERY_TAG == inputs.release-tag &&
vars.RELEASE_RECOVERY_SHA == inputs.release-sha
runs-on: ubuntu-latest
timeout-minutes: 5
outputs:
release-sha: ${{ steps.verify-release.outputs.release-sha }}
release-tag: ${{ steps.verify-release.outputs.release-tag }}
permissions:
contents: read
steps:
- name: Verify the immutable release selected for recovery
id: verify-release
env:
EXPECTED_SHA: ${{ inputs.release-sha }}
EXPECTED_TAG: ${{ inputs.release-tag }}
GH_TOKEN: ${{ github.token }}
run: |
test -n "$EXPECTED_TAG"
test -n "$EXPECTED_SHA"
release=""
for attempt in $(seq 1 12); do
release=$(gh api "repos/${{ github.repository }}/releases/tags/$EXPECTED_TAG") || true
if test -n "$release" && test "$(jq -r .immutable <<<"$release")" = "true"; then
break
fi
if test "$attempt" -ge 12; then
echo "release did not become immutable" >&2
exit 1
fi
sleep 5
done
test "$(jq -r .tag_name <<<"$release")" = "$EXPECTED_TAG"
test "$(jq -r .draft <<<"$release")" = "false"
test "$(jq -r .prerelease <<<"$release")" = "false"
test "$(jq -r .immutable <<<"$release")" = "true"
ref=$(gh api "repos/${{ github.repository }}/git/ref/tags/$EXPECTED_TAG")
tag_type=$(jq -r .object.type <<<"$ref")
tag_sha=$(jq -r .object.sha <<<"$ref")
if test "$tag_type" = "tag"; then
tag_sha=$(gh api "repos/${{ github.repository }}/git/tags/$tag_sha" --jq .object.sha)
else
test "$tag_type" = "commit"
fi
test "$tag_sha" = "$EXPECTED_SHA"
{
echo "release-tag=$EXPECTED_TAG"
echo "release-sha=$EXPECTED_SHA"
echo "release-verified=true"
} >> "$GITHUB_OUTPUT"
publish-release:
name: Run the protected publication recovery
needs: verify-recovery
if: github.run_attempt == 1
permissions:
contents: read
id-token: write
uses: ./.github/workflows/publish.yml
with:
release-tag: ${{ needs.verify-recovery.outputs.release-tag }}
release-sha: ${{ needs.verify-recovery.outputs.release-sha }}
default-branch: ${{ github.event.repository.default_branch }}
secrets: inherit