Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
275 changes: 109 additions & 166 deletions .github/workflows/release-sign.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ permissions:
contents: read

jobs:
build-artifacts:
build-source:
runs-on: ubuntu-latest
permissions:
contents: read
Expand All @@ -32,33 +32,25 @@ jobs:
exit 1
fi

- name: Build deterministic release artifacts
- name: Build deterministic source archives
run: |
set -euo pipefail
./scripts/release/build-artifacts.sh "${GITHUB_REF_NAME}" "${GITHUB_SHA}" dist

- name: Upload release artifact bundle
- name: Upload source release bundle
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: release-artifacts-${{ github.ref_name }}
name: source-release-${{ github.ref_name }}
path: |
dist/ica-${{ github.ref_name }}-source.tar.gz
dist/ica-${{ github.ref_name }}-source.zip
dist/desktop-release-plan.json
dist/desktop-updater-manifest.json
dist/desktop-validation-matrix.json
dist/ica-desktop-${{ github.ref_name }}-macos-x64.dmg
dist/ica-desktop-${{ github.ref_name }}-macos-arm64.dmg
dist/ica-desktop-${{ github.ref_name }}-windows-x64.exe
dist/ica-desktop-${{ github.ref_name }}-windows-arm64.exe
dist/ica-desktop-${{ github.ref_name }}-linux-x64.AppImage
dist/ica-desktop-${{ github.ref_name }}-linux-arm64.AppImage
dist/SHA256SUMS.txt
dist/desktop-validation-matrix.json
if-no-files-found: error

verify-reproducible:
verify-source:
runs-on: ubuntu-latest
needs: build-artifacts
needs: build-source
permissions:
contents: read
steps:
Expand All @@ -67,198 +59,149 @@ jobs:
with:
fetch-depth: 0

- name: Download previously built artifacts
- name: Download source release bundle
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
name: release-artifacts-${{ github.ref_name }}
name: source-release-${{ github.ref_name }}
path: dist-original

- name: Verify downloaded artifacts against checksum manifest
- name: Verify checksums from initial source build
run: |
set -euo pipefail
(cd dist-original && sha256sum -c SHA256SUMS.txt)

- name: Rebuild artifacts independently
- name: Rebuild deterministic source archives
run: |
set -euo pipefail
./scripts/release/build-artifacts.sh "${GITHUB_REF_NAME}" "${GITHUB_SHA}" dist-rebuild

- name: Compare artifact hashes between builds
- name: Compare source checksums between builds
run: |
set -euo pipefail
cp dist-original/SHA256SUMS.txt dist-original/SHA256SUMS.normalized.txt
cp dist-rebuild/SHA256SUMS.txt dist-rebuild/SHA256SUMS.normalized.txt
diff -u dist-original/SHA256SUMS.normalized.txt dist-rebuild/SHA256SUMS.normalized.txt

sign-attest-release:
runs-on: ubuntu-latest
needs:
- build-artifacts
- verify-reproducible
diff -u dist-original/SHA256SUMS.txt dist-rebuild/SHA256SUMS.txt

build-desktop:
strategy:
fail-fast: false
matrix:
include:
- os: macos-latest
target: "--mac dmg"
artifact_glob: "dist/desktop-release/*.dmg\ndist/desktop-release/latest-mac.yml\ndist/desktop-release/*.blockmap"
- os: windows-latest
target: "--win nsis"
artifact_glob: "dist/desktop-release/*.exe\ndist/desktop-release/latest.yml\ndist/desktop-release/*.blockmap"
- os: ubuntu-latest
target: "--linux AppImage"
artifact_glob: "dist/desktop-release/*.AppImage\ndist/desktop-release/latest-linux.yml\ndist/desktop-release/*.blockmap"
runs-on: ${{ matrix.os }}
permissions:
contents: write
contents: read
id-token: write
attestations: write
env:
CSC_LINK: ${{ secrets.CSC_LINK }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Download release artifacts
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Setup Node
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4
with:
name: release-artifacts-${{ github.ref_name }}
path: dist
node-version: 22
cache: npm

- name: Install Cosign
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0
- name: Install dependencies
run: npm ci

- name: Keyless sign release artifacts
run: |
set -euo pipefail
for file in \
"dist/ica-${GITHUB_REF_NAME}-source.tar.gz" \
"dist/ica-${GITHUB_REF_NAME}-source.zip" \
"dist/desktop-release-plan.json" \
"dist/desktop-updater-manifest.json" \
"dist/desktop-validation-matrix.json" \
"dist/ica-desktop-${GITHUB_REF_NAME}-macos-x64.dmg" \
"dist/ica-desktop-${GITHUB_REF_NAME}-macos-arm64.dmg" \
"dist/ica-desktop-${GITHUB_REF_NAME}-windows-x64.exe" \
"dist/ica-desktop-${GITHUB_REF_NAME}-windows-arm64.exe" \
"dist/ica-desktop-${GITHUB_REF_NAME}-linux-x64.AppImage" \
"dist/ica-desktop-${GITHUB_REF_NAME}-linux-arm64.AppImage" \
"dist/SHA256SUMS.txt"
do
cosign sign-blob --yes \
--output-signature "${file}.sig" \
--output-certificate "${file}.pem" \
"${file}"
done
- name: Build signed desktop artifacts
run: npm run build:desktop:release -- ${{ matrix.target }}

- name: Verify signatures against workflow identity
- name: Verify updater metadata exists
shell: bash
run: |
set -euo pipefail
IDENTITY="https://github.com/${GITHUB_REPOSITORY}/.github/workflows/release-sign.yml@${GITHUB_REF}"
ISSUER="https://token.actions.githubusercontent.com"
for file in \
"dist/ica-${GITHUB_REF_NAME}-source.tar.gz" \
"dist/ica-${GITHUB_REF_NAME}-source.zip" \
"dist/desktop-release-plan.json" \
"dist/desktop-updater-manifest.json" \
"dist/desktop-validation-matrix.json" \
"dist/ica-desktop-${GITHUB_REF_NAME}-macos-x64.dmg" \
"dist/ica-desktop-${GITHUB_REF_NAME}-macos-arm64.dmg" \
"dist/ica-desktop-${GITHUB_REF_NAME}-windows-x64.exe" \
"dist/ica-desktop-${GITHUB_REF_NAME}-windows-arm64.exe" \
"dist/ica-desktop-${GITHUB_REF_NAME}-linux-x64.AppImage" \
"dist/ica-desktop-${GITHUB_REF_NAME}-linux-arm64.AppImage" \
"dist/SHA256SUMS.txt"
do
cosign verify-blob \
--certificate "${file}.pem" \
--signature "${file}.sig" \
--certificate-identity "${IDENTITY}" \
--certificate-oidc-issuer "${ISSUER}" \
"${file}"
done

- name: Attest source tarball provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: dist/ica-${{ github.ref_name }}-source.tar.gz

- name: Attest source zip provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: dist/ica-${{ github.ref_name }}-source.zip

- name: Attest checksum manifest provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: dist/SHA256SUMS.txt

- name: Attest desktop release plan provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: dist/desktop-release-plan.json

- name: Attest desktop updater manifest provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: dist/desktop-updater-manifest.json
compgen -G "dist/desktop-release/latest*.yml" >/dev/null

- name: Attest desktop validation matrix provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
- name: Upload desktop release assets
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
subject-path: dist/desktop-validation-matrix.json
name: desktop-${{ matrix.os }}-${{ github.ref_name }}
path: ${{ matrix.artifact_glob }}
if-no-files-found: error

- name: Attest macOS x64 desktop package provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
publish-release:
runs-on: ubuntu-latest
needs:
- verify-source
- build-desktop
permissions:
contents: write
id-token: write
attestations: write
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
steps:
- name: Download source release bundle
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
subject-path: dist/ica-desktop-${{ github.ref_name }}-macos-x64.dmg
name: source-release-${{ github.ref_name }}
path: dist

- name: Attest macOS arm64 desktop package provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
- name: Download macOS desktop assets
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
subject-path: dist/ica-desktop-${{ github.ref_name }}-macos-arm64.dmg
name: desktop-macos-latest-${{ github.ref_name }}
path: dist/desktop

- name: Attest Windows x64 desktop package provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
- name: Download Windows desktop assets
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
subject-path: dist/ica-desktop-${{ github.ref_name }}-windows-x64.exe
name: desktop-windows-latest-${{ github.ref_name }}
path: dist/desktop

- name: Attest Windows arm64 desktop package provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
- name: Download Linux desktop assets
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
with:
subject-path: dist/ica-desktop-${{ github.ref_name }}-windows-arm64.exe
name: desktop-ubuntu-latest-${{ github.ref_name }}
path: dist/desktop

- name: Attest Linux x64 desktop package provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: dist/ica-desktop-${{ github.ref_name }}-linux-x64.AppImage
- name: Install Cosign
uses: sigstore/cosign-installer@dc72c7d5c4d10cd6bcb8cf6e3fd625a9e5e537da # v3.7.0

- name: Attest Linux arm64 desktop package provenance
uses: actions/attest-build-provenance@e8998f949152b193b063cb0ec769d69d929409be # v2
with:
subject-path: dist/ica-desktop-${{ github.ref_name }}-linux-arm64.AppImage
- name: Keyless sign release assets
shell: bash
run: |
set -euo pipefail
while IFS= read -r file; do
cosign sign-blob --yes \
--output-signature "${file}.sig" \
--output-certificate "${file}.pem" \
"${file}"
done < <(find dist -type f \( -name '*.gz' -o -name '*.zip' -o -name '*.dmg' -o -name '*.exe' -o -name '*.AppImage' -o -name 'latest*.yml' -o -name '*.blockmap' -o -name 'SHA256SUMS.txt' -o -name 'desktop-validation-matrix.json' \) | sort)

- name: Publish GitHub release with signed assets
- name: Create draft GitHub release
uses: softprops/action-gh-release@a06a81a03ee405af7f2048a818ed3f03bbf83c7b # v2
with:
tag_name: ${{ github.ref_name }}
generate_release_notes: true
draft: true
fail_on_unmatched_files: true
files: |
dist/ica-${{ github.ref_name }}-source.tar.gz
dist/ica-${{ github.ref_name }}-source.tar.gz.sig
dist/ica-${{ github.ref_name }}-source.tar.gz.pem
dist/ica-${{ github.ref_name }}-source.zip
dist/ica-${{ github.ref_name }}-source.zip.sig
dist/ica-${{ github.ref_name }}-source.zip.pem
dist/desktop-release-plan.json
dist/desktop-release-plan.json.sig
dist/desktop-release-plan.json.pem
dist/desktop-updater-manifest.json
dist/desktop-updater-manifest.json.sig
dist/desktop-updater-manifest.json.pem
dist/desktop-validation-matrix.json
dist/desktop-validation-matrix.json.sig
dist/desktop-validation-matrix.json.pem
dist/ica-desktop-${{ github.ref_name }}-macos-x64.dmg
dist/ica-desktop-${{ github.ref_name }}-macos-x64.dmg.sig
dist/ica-desktop-${{ github.ref_name }}-macos-x64.dmg.pem
dist/ica-desktop-${{ github.ref_name }}-macos-arm64.dmg
dist/ica-desktop-${{ github.ref_name }}-macos-arm64.dmg.sig
dist/ica-desktop-${{ github.ref_name }}-macos-arm64.dmg.pem
dist/ica-desktop-${{ github.ref_name }}-windows-x64.exe
dist/ica-desktop-${{ github.ref_name }}-windows-x64.exe.sig
dist/ica-desktop-${{ github.ref_name }}-windows-x64.exe.pem
dist/ica-desktop-${{ github.ref_name }}-windows-arm64.exe
dist/ica-desktop-${{ github.ref_name }}-windows-arm64.exe.sig
dist/ica-desktop-${{ github.ref_name }}-windows-arm64.exe.pem
dist/ica-desktop-${{ github.ref_name }}-linux-x64.AppImage
dist/ica-desktop-${{ github.ref_name }}-linux-x64.AppImage.sig
dist/ica-desktop-${{ github.ref_name }}-linux-x64.AppImage.pem
dist/ica-desktop-${{ github.ref_name }}-linux-arm64.AppImage
dist/ica-desktop-${{ github.ref_name }}-linux-arm64.AppImage.sig
dist/ica-desktop-${{ github.ref_name }}-linux-arm64.AppImage.pem
dist/SHA256SUMS.txt
dist/SHA256SUMS.txt.sig
dist/SHA256SUMS.txt.pem
dist/desktop-validation-matrix.json
dist/desktop/**/*.dmg
dist/desktop/**/*.exe
dist/desktop/**/*.AppImage
dist/desktop/**/latest*.yml
dist/desktop/**/*.blockmap
dist/**/*.sig
dist/**/*.pem

- name: Publish release only after validation passes
run: gh release edit "${GITHUB_REF_NAME}" --draft=false
Loading
Loading