diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ea8bcb6..116ba29 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -148,7 +148,7 @@ jobs: shell: bash run: | set -euo pipefail - if gh release view "${GITHUB_REF_NAME}" >/dev/null 2>&1; then + if gh release view "${GITHUB_REF_NAME}" --repo "${GITHUB_REPOSITORY}" >/dev/null 2>&1; then echo "::error::release ${GITHUB_REF_NAME} already exists; release tags are write-once" >&2 exit 1 fi @@ -167,7 +167,7 @@ jobs: run: | set -euo pipefail mkdir -p verify - gh release download "${GITHUB_REF_NAME}" --dir verify + gh release download "${GITHUB_REF_NAME}" --repo "${GITHUB_REPOSITORY}" --dir verify test "$(find verify -maxdepth 1 -name '*.tar.gz' | wc -l | tr -d ' ')" = "3" test "$(find verify -maxdepth 1 -name '*.tar.gz.sha256' | wc -l | tr -d ' ')" = "3" for checksum in verify/*.tar.gz.sha256; do diff --git a/.github/workflows/verify-release.yml b/.github/workflows/verify-release.yml new file mode 100644 index 0000000..85be8cf --- /dev/null +++ b/.github/workflows/verify-release.yml @@ -0,0 +1,55 @@ +name: Verify Existing Release + +on: + workflow_dispatch: + inputs: + tag: + description: Existing immutable release tag to verify. + required: true + type: string + +permissions: + contents: read + +concurrency: + group: queue-verify-release-${{ inputs.tag }} + cancel-in-progress: false + +jobs: + verify: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Validate immutable tag and published release + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ inputs.tag }} + shell: bash + run: | + set -euo pipefail + [[ "${RELEASE_TAG}" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]] + git rev-parse --verify "refs/tags/${RELEASE_TAG}^{commit}" + gh release view "${RELEASE_TAG}" --repo "${GITHUB_REPOSITORY}" \ + --json isDraft,isPrerelease,tagName \ + --jq 'select(.isDraft == false and .isPrerelease == false and .tagName == env.RELEASE_TAG)' + + - name: Verify all published assets against bound checksums + env: + GH_TOKEN: ${{ github.token }} + RELEASE_TAG: ${{ inputs.tag }} + shell: bash + run: | + set -euo pipefail + mkdir -p verify + gh release download "${RELEASE_TAG}" --repo "${GITHUB_REPOSITORY}" --dir verify + test "$(find verify -maxdepth 1 -name '*.tar.gz' | wc -l | tr -d ' ')" = "3" + test "$(find verify -maxdepth 1 -name '*.tar.gz.sha256' | wc -l | tr -d ' ')" = "3" + for checksum in verify/*.tar.gz.sha256; do + archive="${checksum%.sha256}" + expected="$(tr -d '[:space:]' < "${checksum}")" + actual="$(sha256sum "${archive}" | awk '{print $1}')" + test "${actual}" = "${expected}" + done