ci(release): attest release and nightly build artifacts (#4851)

Add actions/attest-build-provenance to both build workflows so every
binary is attested in the same job that builds it, the only point
where provenance meaningfully proves an artifact was built from source
rather than uploaded by hand.

release.yml (build-tauri): grant id-token and attestations write
permissions, then attest the desktop bundles via the tauri-action
artifactPaths output, the Android apks, and the Windows portable exe.

nightly.yml (build): same permissions plus one step attesting the
staged nightly-out binaries. Nightlies ship via download.readest.com,
but gh attestation verify is digest based so it verifies them too.

Verify a download with:
  gh attestation verify <file> --repo readest/readest

Closes #4848

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Huang Xin
2026-06-29 10:14:21 +08:00
committed by GitHub
parent a23427ccc6
commit 781a297993
2 changed files with 50 additions and 0 deletions
+18
View File
@@ -40,6 +40,12 @@ jobs:
build:
needs: compute-version
permissions:
contents: read
# Required by actions/attest-build-provenance: id-token mints the Sigstore
# OIDC identity, attestations writes the provenance to the repo's store.
id-token: write
attestations: write
strategy:
fail-fast: false
matrix:
@@ -381,6 +387,18 @@ jobs:
;;
esac
# Attest the distributable binaries staged in nightly-out (apks, AppImage,
# app.tar.gz, setup/portable exe). gh attestation verify is digest-based,
# so it verifies these against readest/readest even though they ship via
# download.readest.com rather than a GitHub release. The .sig updater
# signatures are excluded — they are not binaries users run.
- name: attest nightly binaries
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: |
nightly-out/Readest*
!nightly-out/*.sig
- name: upload artifacts + fragment to R2
shell: bash
run: |
+32
View File
@@ -122,6 +122,10 @@ jobs:
needs: get-release
permissions:
contents: write
# Required by actions/attest-build-provenance: id-token mints the Sigstore
# OIDC identity, attestations writes the provenance to the repo's store.
id-token: write
attestations: write
strategy:
fail-fast: false
matrix:
@@ -267,6 +271,14 @@ jobs:
gh release upload ${{ needs.get-release.outputs.release_tag }} $universial_apk.sig --clobber
gh release upload ${{ needs.get-release.outputs.release_tag }} $arm64_apk.sig --clobber
- name: attest Android apks
if: matrix.config.release == 'android'
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: |
apps/readest-app/Readest_${{ needs.get-release.outputs.release_version }}_universal.apk
apps/readest-app/Readest_${{ needs.get-release.outputs.release_version }}_arm64.apk
- name: download and update latest.json for Android release
if: matrix.config.release == 'android'
env:
@@ -309,6 +321,7 @@ jobs:
run: cargo install tauri-cli --git https://github.com/tauri-apps/tauri --branch feat/truly-portable-appimage --force
- uses: tauri-apps/tauri-action@84b9d35b5fc46c1e45415bdb6144030364f7ebc5 # v0
id: tauri
if: matrix.config.release != 'android'
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -332,6 +345,16 @@ jobs:
releaseBody: ${{ needs.get-release.outputs.release_note }}
args: ${{ matrix.config.args || '' }}
# Attest the freshly built desktop bundles (installers, AppImage, dmg,
# updater archives + their .sig). tauri-action reports their on-disk paths
# as a JSON array; fromJSON('"\n"') yields a real newline to join them into
# the newline-delimited list subject-path expects.
- name: attest desktop bundles
if: matrix.config.release != 'android' && steps.tauri.outputs.artifactPaths != ''
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: ${{ join(fromJSON(steps.tauri.outputs.artifactPaths), fromJSON('"\n"')) }}
- name: upload release notes to GitHub release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
@@ -384,6 +407,15 @@ jobs:
echo "Uploading signature to GitHub release"
gh release upload ${{ needs.get-release.outputs.release_tag }} $bin_file.sig --clobber
# The portable rebuild above is not produced by tauri-action, so it is not
# covered by the "attest desktop bundles" step; attest it here. Exactly one
# portable exe is staged at the workspace root per Windows leg.
- name: attest Windows portable binary
if: matrix.config.os == 'windows-latest'
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
with:
subject-path: Readest_*-portable.exe
- name: download and update latest.json for Windows portable release
if: matrix.config.os == 'windows-latest'
env: