-
-
Notifications
You must be signed in to change notification settings - Fork 3
release pipeline
Status: shipped.
A v* tag builds installers for four targets, adds SBOMs, debug symbols and checksums, signs every file with Sigstore, and makes a draft GitHub release.
- A push of a tag that matches
v*startsrelease.yml. A manual run (workflow_dispatch) does the same, with thedry_runinput. - The
gatesjob runsscripts/release-gates.sh. It reads the required checks from the active ruleset of the default branch. It fails when the tagged commit is not onmain, or when a required check has nosuccessrun on that commit or on the head of the pull request that merged it. Some required checks, such asdocs-check, run on pull requests only. Thebuildjob needsgates. The release no longer callslint.yml,security.ymlorci.yml. - The
buildjob has four legs. Each uses the Tauri CLI with no third-party release action:-
scripts/repro-env.shsetsSOURCE_DATE_EPOCH,CARGO_INCREMENTAL=0and--remap-path-prefix. See Reproducible builds. -
npx tauri build --no-bundle -- --lockedbuilds the release binary. -
scripts/split-debug.shmoves the debug symbols into a separate file (see below). - On Linux,
scripts/check-hardening.shchecks PIE, full RELRO and NX. -
npx tauri bundlebuilds the installers from the stripped binary.
-
x86_64-pc-windows-msvconwindows-2025: NSIS installer. -
aarch64-apple-darwinonmacos-15:.dmg. -
x86_64-apple-darwinonmacos-15:.dmg. -
x86_64-unknown-linux-gnuonubuntu-24.04: AppImage and.deb.
-
- The
sbomjob writes two CycloneDX files. One is for the Rust crates (cargo cyclonedx). One is for the npm production dependencies (npm sbom). - The
publishjob flattens all artifacts into one folder and writesSHA256SUMSfor every file. - The same job signs every file,
SHA256SUMSincluded, with Sigstorecosign sign-blob. The signature is keyless: the job's OIDC token gets a short-lived certificate from Fulcio, and the Rekor transparency log records each signature. Each file gets a<file>.sigstore.jsonbundle. The job then runscosign verify-blobon every bundle against the identity of this workflow run, and fails on a bad signature. - The same job attests build provenance with
actions/attest-build-provenance. - The same job writes the release notes with git-cliff (see Changelog and release notes).
- Last,
gh release create --draft --notes-fileuploads the files and the.sigstore.jsonbundles. A person reads the draft and publishes it.
- Nobody edits
CHANGELOG.mdin a PR. This stops the merge conflicts that a shared line caused.docs-checkfails a PR that changes it. - git-cliff builds the changelog and the release notes from the Conventional Commit titles on
main.cliff.tomlgroupsfeatunder Added,fixunder Fixed,securityunder Security,perfandrefactorunder Changed, anddocs,ci,testandchoreunder their own sections. It links each(#N)to its pull request and skips merge commits. - The squash-merge title is the commit title. Write a clear Conventional Commit PR title.
-
scripts/release-notes.shprints the notes for one tag: the commits since the previousv*tag. Thepublishjob installs a pinned git-cliff withscripts/install-git-cliff.sh, which checks the SHA-256 of the download. The notes become the draft release body. - The release job writes the release notes. It does not commit
CHANGELOG.md, becausemainis protected.CHANGELOG.mdis a snapshot of the generated history. A maintainer refreshes it in a PR withscripts/changelog.sh --write origin/main. It needs git-cliff (brew install git-cliff). -
docs-checkaccepts aCHANGELOG.mdchange only when the file equals the output ofscripts/changelog.shfor the base branch tip, or for the commit where the PR branched off. A merge tomainafter that does not turn the PR red.
| File | What it is |
|---|---|
eepview_<version>_x64-setup.exe |
Windows NSIS installer |
eepview_<version>_aarch64.dmg, eepview_<version>_x64.dmg
|
macOS disk images |
eepview_<version>_amd64.AppImage, eepview_<version>_amd64.deb
|
Linux packages |
eepview-<target>.debug |
Linux debug symbols (DWARF), split with objcopy --only-keep-debug
|
eepview-<target>.dSYM.zip |
macOS debug symbols (split-debuginfo = "packed") |
eepview-<target>.pdb |
Windows debug symbols |
eepview.cdx.json, npm.cdx.json
|
CycloneDX SBOMs for the Rust crates and the npm packages |
SHA256SUMS |
SHA-256 of every file above |
<file>.sigstore.json |
Sigstore bundle (signature, certificate, Rekor entry) for each file |
The debug symbols hold function names and line tables (debug = "limited"). The shipped binaries are stripped. To read a Linux crash backtrace, put eepview-x86_64-unknown-linux-gnu.debug next to the binary; the binary has a .gnu_debuglink to it. On macOS, unzip the .dSYM next to the app, or pass it to atos -o.
Check the Sigstore signature. The certificate must name release.yml on a v* tag of this repo:
cosign verify-blob \
--bundle eepview_0.1.0_amd64.deb.sigstore.json \
--certificate-identity-regexp '^https://github.com/tcivie/eepview/.github/workflows/release.yml@refs/tags/v' \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
eepview_0.1.0_amd64.debCheck the build provenance with the GitHub CLI:
gh attestation verify eepview_0.1.0_amd64.deb --repo tcivie/eepviewCheck the hash. Verify SHA256SUMS itself first, with the two commands above, then:
sha256sum --check --ignore-missing SHA256SUMS- Dry run. It builds, signs and verifies everything, but skips the attestation and the release:
gh workflow run release.yml -f dry_run=true --ref main
- Real release. Bump the version, merge it, then push a signed tag from
main. See Release and support.git tag -s v0.1.0 -m "eepview v0.1.0" && git push origin v0.1.0
- Open the draft release, check the files and
SHA256SUMS, then publish it.
-
publishattests and releases only for arefs/tags/v*ref that is not a dry run. A manual run on a branch never makes a release. It still signs the files, so each dry run adds entries to the public Rekor log. - A dry run signs with the identity of its own ref (
refs/heads/...). Those signatures do not match therefs/tags/vpattern above, by design. - The macOS release ships only the
.dmg.bundle.macOS.signingIdentityis-insrc-tauri/tauri.conf.json, so the Tauri bundler ad-hoc signs the.appbefore it builds the.dmg. A build step mounts the.dmgand runscodesign --verify --deep --strictandcodesign -dvon the app. It fails unless the report saysSignature=adhoc. There is no Developer ID signature and no notarization. - Windows installers are not signed.
- The
gatesjob skips its check on a branch dry run, so a pipeline change can be tested before merge. It needs a greenmainat the tagged commit. A dry run onmainfails while the checks ofmainHEAD are red or still running. - The pipeline has no lint exclusion. actionlint and
zizmor --offline --persona=pedanticreport nothing.
- #14: release pipeline with SBOM, checksums and provenance.
- #24: release gates job without lint exclusions; the macOS app is signed inside the dmg.
- #37: Sigstore signatures for every release file, provenance without the private-repo guard, separate debug symbols, repeatable build environment.
- #39: the gate also reads the checks of the merged PR head.
-
#47: permission comments in
release.yml; zizmor runs with the pedantic persona. - #50: generated changelog and release notes from commit titles with git-cliff.
Generated from docs/wiki in the repository. Edit there, not here.