diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index d2c8da2..ffe38d2 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -11,12 +11,9 @@ on: - "v[0-9]+.[0-9]+.[0-9]+" workflow_dispatch: -env: - BUILD_URL: "${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - jobs: - publish: - name: Publish + build: + name: build strategy: matrix: kind: ['linux', 'windows'] @@ -58,14 +55,11 @@ jobs: retention-days: 1 if-no-files-found: error - release: - name: Release - needs: publish + publish: + name: Publish + needs: build runs-on: ubuntu-latest steps: - - name: Checkout - uses: actions/checkout@v4 - - name: Download artifacts uses: actions/download-artifact@v4 with: @@ -79,12 +73,47 @@ jobs: run: ci/checksums.sh - name: Generate artifact attestation + id: attest uses: actions/attest-build-provenance@v2 with: subject-checksums: artifacts/shasum.txt + - name: Create job outputs + id: job-info + run: ci/create-job-outputs.sh >> $GITHUB_OUTPUT + outputs: + attestation_url: ${{ steps.attest.outputs.attestation-url }} + checksum_url: ${{ steps.job-info.outputs.checksum_url }} + job_id: ${{ steps.job-info.outputs.job_id }} + + archive-job-log: + name: Archive Job Log + needs: publish + runs-on: ubuntu-latest + steps: + - name: Archive + run: ci/archive-job-log.sh ${{ needs.publish.outputs.job_id }} >> $GITHUB_OUTPUT + outputs: + archived_job_url: ${{ steps.archive.outputs.archived_url }} + + release: + name: Release + needs: [ publish, archive-job-log ] + if: needs.publish.result == 'success' && needs.archive-job-log.result != 'cancelled' + runs-on: ubuntu-latest + steps: + - name: Download artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + merge-multiple: true + - name: Create Release Notes - run: ci/release-notes.sh + env: + ATTESTATION_URL: ${{ needs.publish.outputs.attestation_url }} + CHECKSUM_URL: ${{ needs.publish.outputs.checksum_url }} + ARCHIVED_JOB_URL: ${{ needs.archive-job-log.outputs.archived_job_url }} + run: ci/release-notes.sh > release-notes.md - name: Release uses: softprops/action-gh-release@v1 diff --git a/ci/archive-job-log.sh b/ci/archive-job-log.sh new file mode 100644 index 0000000..8d69867 --- /dev/null +++ b/ci/archive-job-log.sh @@ -0,0 +1,30 @@ +#!/bin/bash +set -e + +job_id="$1" +raw_log_url=$(curl -Ls -o /dev/null \ + -w %{url_effective} \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/${GITHUB_REPOSITORY}/actions/jobs/$job_id/logs +) +archived_url=$(curl -L -s -o /dev/null -w "%header{link}" "http://web.archive.org/save/$raw_log_url" \ + | awk '/^/, "", link) # remove angle brackets + gsub(/^ *| *$/, "", link) # remove leading/trailing whitespace + + if(link ~ "rel=\"memento\"") { + split(link, parts, ";") + gsub(/^http:/, "https:", parts[1]) + print parts[1] + } + } + }' +) +echo "archived_url=$archived_url" \ No newline at end of file diff --git a/ci/create-job-outputs.sh b/ci/create-job-outputs.sh new file mode 100644 index 0000000..fae3b55 --- /dev/null +++ b/ci/create-job-outputs.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +job_name=Publish +step_name="Create Checksums" +job=$(curl -Ls \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN"\ + -H "X-GitHub-Api-Version: 2022-11-28" \ + https://api.github.com/repos/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID/attempts/$GITHUB_RUN_ATTEMPT/jobs \ + | jq -r ".jobs[] | select(.name==\"$job_name\")" +) +run_url=$(echo "$job" | jq -r .html_url) +checksum_number=$(echo "$job" | jq ".steps[] | select(.name==\"$step_name\") | .number") + +echo "checksum_url=$run_url#step:$checksum_number:1" +echo "job_id=$GITHUB_JOB" \ No newline at end of file diff --git a/ci/release-notes.sh b/ci/release-notes.sh index 3b915ca..105e5bc 100755 --- a/ci/release-notes.sh +++ b/ci/release-notes.sh @@ -2,22 +2,23 @@ set -e root=$(dirname "$(readlink -f "$0")")/.. -release_notes="$root"/release-notes.md artifact_name=$(find "$root/artifacts" -type f -name 'min*' -printf "%f\n" -quit) -"$root"/ci/latest-changes.sh > "$release_notes" -cat << EOF >> "$release_notes" +"$root"/ci/latest-changes.sh +cat << EOF ----- Verify the release artifacts are built from source by Github by either: - 1. Using the [Github CLI] to verify the integrity and provenance using its associated cryptographically [signed attestations] + 1. Using the [Github CLI] to [verify] the integrity and provenance using its associated cryptographically [signed attestations] \`gh attestation verify $artifact_name -R rfvgyhn/min-ed-launcher\` - 2. Comparing the _shasum.txt_ contents with the _Create Checksums_ section of the job log of the [automated release] + 2. Comparing the _shasum.txt_ contents with the _Create Checksums_ section of the job log of the [automated release] ([archive]) See [wiki] for instructions on how to check the checksums of the release artifacts. -[automated release]: ${BUILD_URL:-https://github.com/rfvgyhn/min-ed-launcher/actions} +[automated release]: ${CHECKSUM_URL:-https://github.com/rfvgyhn/min-ed-launcher/actions} [wiki]: https://github.com/rfvgyhn/min-ed-launcher/wiki/Verify-Checksums-for-a-Release [Github CLI]: https://cli.github.com/ -[signed attestations]: https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds +[verify]: https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds +[signed attestations]: ${ATTESTATION_URL:-https://github.com/rfvgyhn/min-ed-launcher/attestations} +[archive]: $ARCHIVED_JOB_URL EOF \ No newline at end of file