Recover immutable release publication #1
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |