Files
webmail/.github/workflows/standalone-release.yml
T
Linus Rath 569c796522 ci: sign published images and release files with build provenance
Nothing showed where a published image or download came from, and the
standalone tarballs had no checksum at all. Anyone who could swap a
release asset could swap its `.sha256` with it.

- every published image (release, `-always`, beta/dev and Lite) gets a
  signed build provenance attestation, pushed to GHCR next to it
- the Lite zips and standalone tarballs are attested as well
- standalone tarballs get a `.sha256`, like the Lite zips
- the tarball build no longer holds a write token: a separate release
  job, which runs no checked-out code, checksums, attests and uploads
- the README says how to check with `gh attestation verify`
2026-09-27 15:22:17 +02:00

100 lines
2.6 KiB
YAML

name: Publish Standalone Tarball on Release
# The tarballs build without a write token. The release job, which runs no
# checked-out code, publishes each one with a `.sha256` next to it and a
# signed build provenance attestation:
# `gh attestation verify <tarball> --repo bulwarkmail/webmail`.
on:
release:
types: [published]
workflow_dispatch:
permissions:
contents: read
jobs:
build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
arch: amd64
- os: ubuntu-24.04-arm
arch: arm64
runs-on: ${{ matrix.os }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
- name: Install dependencies
run: npm ci
- name: Build standalone
run: npm run build
- name: Package tarball
env:
REF_NAME: ${{ github.ref_name }}
ARCH: ${{ matrix.arch }}
run: |
VERSION="${REF_NAME#v}"
TARBALL="bulwark-standalone-${VERSION}-linux-${ARCH}.tar.gz"
mkdir -p bulwark-standalone
cp -r .next/standalone/. bulwark-standalone/
cp -r .next/static bulwark-standalone/.next/static
cp -r public bulwark-standalone/public
tar -czf "$TARBALL" bulwark-standalone/
echo "TARBALL=$TARBALL" >> "$GITHUB_ENV"
- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: standalone-${{ matrix.arch }}
path: ${{ env.TARBALL }}
if-no-files-found: error
retention-days: 7
release:
needs: build
if: github.event_name == 'release'
runs-on: ubuntu-latest
timeout-minutes: 10
permissions:
contents: write
id-token: write
attestations: write
steps:
- name: Download tarballs
uses: actions/download-artifact@v4
with:
pattern: standalone-*
path: tarballs
merge-multiple: true
- name: Checksum tarballs
working-directory: tarballs
run: for tarball in *.tar.gz; do sha256sum "$tarball" > "$tarball.sha256"; done
- name: Attest build provenance
uses: actions/attest@v4
with:
subject-path: tarballs/*.tar.gz
- name: Upload release assets
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GH_REPO: ${{ github.repository }}
TAG_NAME: ${{ github.event.release.tag_name }}
run: gh release upload "$TAG_NAME" tarballs/*.tar.gz tarballs/*.tar.gz.sha256 --clobber