Repository navigation
Release pipeline, packaging and distribution docs - #1
Conversation
- release.yml: builds the macOS DMG, Linux .deb and Windows NSIS installer on their own runners from the viewer pin, with no cache. On macOS a fresh sync must reproduce the committed viewer-dist. Each job runs the tests and checks its package: strict codesign, a glibc floor covering every ELF in the .deb, and notices plus the native engine inside the installer. A v* tag also drafts the release with notices, MPL sources, SHA256SUMS and build-provenance attestations. Publishing stays manual. - scripts/release: version agreement across the three version files and the tag, MPL-2.0 crate collection verified against Cargo.lock, and an assembler that owns asset names and refuses a missing or unexpected asset. - Packaging: THIRD_PARTY_NOTICES.txt, LICENSE.md and third-party/ ship inside every package. Linux builds only .deb and declares libc6 >= 2.38, which the native engine needs. tauri.macos.conf.json signs ad-hoc with the hardened runtime, so local and CI bundles pass strict verification without a manual codesign step.
- README: an Install section with checksum and attestation verification, the macOS Open Anyway step, SmartScreen and Smart App Control on Windows, the Linux glibc floor, and uninstall steps for each platform. - docs/code-signing-policy.md: the signing status of each package, what SignPath signing will and will not cover (the upstream tjs.exe stays unsigned), roles, and the privacy statement. - release-readiness: the pipeline, notices, AppImage and glibc gates, plus the release procedure.
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5a4a09c15c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| [code signing policy](docs/code-signing-policy.md). Verify a download before | ||
| installing it: | ||
|
|
||
| ```sh |
There was a problem hiding this comment.
Add native checksum commands for macOS and Windows
For users following the new macOS or Windows installation paths on a stock system, sha256sum is unavailable, so the prescribed checksum verification cannot be run as written. Provide platform-specific alternatives such as shasum -a 256 on macOS and Get-FileHash on Windows, or explicitly document the additional GNU tooling required.
Useful? React with 👍 / 👎.
| REF_NAME: ${{ github.ref_name }} | ||
| RUN_URL: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }} | ||
| run: | | ||
| cp THIRD_PARTY_NOTICES.txt dist/ |
There was a problem hiding this comment.
Regenerate release-specific third-party notices
For this v0.2.0 release and every future version, copying the static notice ships text headed “0.2.0 private beta” that directs recipients to v0.2.0-beta.1 for the MPL source archive, even though the workflow attaches the corresponding archive to the current tag. Generate or validate the notice against REF_NAME before packaging it so installed copies identify the actual release and source location.
Useful? React with 👍 / 👎.
| GH_TOKEN: ${{ github.token }} | ||
| REF_NAME: ${{ github.ref_name }} | ||
| run: | | ||
| gh release create "$REF_NAME" dist/* --repo "$GITHUB_REPOSITORY" --draft --verify-tag \ |
There was a problem hiding this comment.
Mark prerelease tags as prereleases
When a supported tag such as v0.3.0-beta.1 triggers this workflow, the draft is created without --prerelease; publishing it according to the documented procedure therefore exposes the beta as an ordinary release and may let it become Latest. The gh release create manual documents --prerelease as the flag that marks this state, so add it conditionally when the validated version contains a prerelease component.
Useful? React with 👍 / 👎.
|
|
||
| | Package | Signature | | ||
| | --- | --- | | ||
| | macOS `.dmg` | Ad-hoc signature with the hardened runtime. Not signed with an Apple Developer ID and not notarized. | |
There was a problem hiding this comment.
Describe the DMG itself as unsigned
The policy currently reports the .dmg as ad-hoc signed, but with signingIdentity: "-" Tauri deliberately skips signing the disk image and only ad-hoc signs the contained .app; the workflow likewise runs codesign on the app and only hdiutil verify on the DMG. The Tauri DMG bundler explicitly skips self-signing DMGs for this identity, so describe the DMG as unsigned and the enclosed app as ad-hoc signed to avoid overstating the package’s signature status.
Useful? React with 👍 / 👎.
Found by the first run of the release workflow: - Windows: two source-scanning shell tests failed because the runner's checkout converted lib.rs to CRLF, so "#[cfg(test)]\nmod tests" was never found. .gitattributes now checks out every text file as LF on every platform, which also keeps the sha256-manifested viewer-dist byte-exact. The index holds no CRLF, so no content changes. - Linux: the glibc-floor check caught the app binary built on Ubuntu 24.04 needing GLIBC_2.39, above the declared 2.38. The .deb now declares libc6 (>= 2.39); Ubuntu 24.04 and Debian 13 still qualify. - The .deb is named sq-lite-explorer (Tauri derives it from the product name), so the README's uninstall command was wrong. Add a short and long description in place of the control file's "(none)".
- THIRD_PARTY_NOTICES.txt still read "0.2.0 private beta" and sent MPL source requests to releases/tag/v0.2.0-beta.1. That tag never existed in this repository, so every package would ship a broken source pointer. The header is now version-neutral and points at the release page, which carries mpl-dependency-sources.tar.gz. - A prerelease tag drafted an ordinary release, which publishing could make Latest. The manifest now records prerelease, and the workflow adds --prerelease from it. - The DMG was described as ad-hoc signed. Only the app inside is (Tauri skips the disk image for identity "-"; codesign reports the DMG "not signed at all"). The docs and the manifest now say so. - sha256sum does not exist on Windows. The notes now give shasum for macOS, sha256sum for Linux and a PowerShell Get-FileHash check for Windows. That command comes from one exported function, and the Windows build job runs that exact string against its own installer: True for the real hash, False for a wrong one. Regression tests for the notices, prerelease, DMG wording and checksum commands failed before this change and pass after it.
* release: 0.3.0 Version bump for the first public release. Changes since the 0.2.0 private beta: the navigation pin and CSP base-uri/form-action/frame-ancestors, the hardened-runtime ad-hoc macOS signature, notices bundled in every package, a .deb-only Linux release with a glibc 2.39 floor, and the release workflow. * fix(release): address the Codex review findings on #1 and #2 - THIRD_PARTY_NOTICES.txt still read "0.2.0 private beta" and sent MPL source requests to releases/tag/v0.2.0-beta.1. That tag never existed in this repository, so every package would ship a broken source pointer. The header is now version-neutral and points at the release page, which carries mpl-dependency-sources.tar.gz. - A prerelease tag drafted an ordinary release, which publishing could make Latest. The manifest now records prerelease, and the workflow adds --prerelease from it. - The DMG was described as ad-hoc signed. Only the app inside is (Tauri skips the disk image for identity "-"; codesign reports the DMG "not signed at all"). The docs and the manifest now say so. - sha256sum does not exist on Windows. The notes now give shasum for macOS, sha256sum for Linux and a PowerShell Get-FileHash check for Windows. That command comes from one exported function, and the Windows build job runs that exact string against its own installer: True for the real hash, False for a wrong one. Regression tests for the notices, prerelease, DMG wording and checksum commands failed before this change and pass after it. * ci(release): fail when the third-party notices drift from the release graph THIRD_PARTY_NOTICES.txt and third-party/inventory.json were generated once and nothing regenerated or checked them. A dependency bump would have shipped incomplete notices in every package without anything failing. scripts/release/notices.mjs checks that: - the inventory's Cargo components are exactly the packages a release resolves. This uses `cargo metadata` with default features. The raw lock would wrongly demand the 26 qa-webdriver-only crates, which no release builds; - the inventory was built for viewer-dist's pin; - every inventoried component has a section in the notices. It runs in CI, so a dependency-bump PR goes red, and in every release build. Today it passes: the release resolves 442 packages and the inventory lists exactly those 442. With one shipped crate removed from the inventory it fails and names the crate. ci.yml also moves to the Node-24 action SHAs release.yml already uses.
Problem
There was no repeatable way to produce release packages. The private beta's installers, notice bundle and MPL source archive were assembled by hand on separate machines. The readiness doc therefore left several binary-distribution gates open:
Solution
A release workflow that builds each package on its own OS from the committed viewer pin and verifies it. Pushing a
v*tag also drafts a GitHub release carrying everything the licenses and users need. Publishing stays manual.Signing decisions for this release:
.debonly; no AppImage.Architecture
.github/workflows/release.ymlruns a three-way matrix:macos-latest(DMG),ubuntu-24.04(.deb) andwindows-latest(NSIS). Each build job:viewer-dist/exactly;npm testandcargo test --lib;codesignverification, notices andtjsinside the app,hdiutil verify;tjsin the.deb, and a declaredlibc6floor that every packaged ELF must satisfy;tjs.exeinside the installer;scripts/release/assemble.mjsassigns it.The
releasejob runs only for a tag. It downloads the three packages and addsTHIRD_PARTY_NOTICES.txtand the MPL sources.assemblerefuses a missing or unexpected asset, then writesrelease-manifest.json,SHA256SUMSand the notes. Every asset gets a build-provenance attestation, and the job creates a draft release.Per-file changes
.github/workflows/release.yml(new): the pipeline above. Pull requests that touch the pipeline run the build jobs only.scripts/release/version.mjs(new): enforces version agreement acrosspackage.json,Cargo.tomlandtauri.conf.json, plus the tag.scripts/release/mpl-sources.mjs(new): collects every MPL-obligating crate in the lock graph.MIT OR MPL-2.0doesn't count; shapes it can't parse are included anyway. Each.crateis downloaded and its SHA256 checked againstCargo.lock.scripts/release/assemble.mjs(new): owns the asset names and writes the manifest, checksums and notes.scripts/release/release.test.mjs(new): 9 tests, now part ofnpm test.src-tauri/tauri.conf.json: bundlesLICENSE.md,THIRD_PARTY_NOTICES.txtandthird-party/into every package.src-tauri/tauri.linux.conf.json: builds.debonly and declareslibc6 (>= 2.39): the nativetjsengine needsGLIBC_2.38and the app built on 24.04 needs 2.39.src-tauri/tauri.macos.conf.json(new):signingIdentity: "-", so Tauri ad-hoc signs the app, hardened runtime included..gitattributes(new): LF checkouts on every platform.src-tauri/src/lib.rs: theuseHttpsSchemelockstep test also reads the new macOS config.README.md: a new Install section: verification, the macOS Open Anyway step, SmartScreen and Smart App Control on Windows, the Linux glibc floor, and uninstall steps for each platform. The build section drops the manualcodesignstep.docs/code-signing-policy.md(new): the SignPath-required page. It covers signing status, what signing will and won't cover, roles, and the privacy statement, including the WebView2 bootstrapper download.docs/release-readiness.md,third-party/README.md: updated gates and the release procedure.Security
persist-credentials: falseeverywhere.${{ }}reaches the shell throughenv:.contents: read. Only the tag-onlyreleasejob getscontents: write,id-token: writeandattestations: write.pull_request, neverpull_request_target, and the build jobs use no secrets.Cargo.lock. The assembler refuses a polluted dist directory, so nothing unexpected gets attached.Test plan
npm test: 23/23, including the 9 new release-script tests: version drift, MPL selection, tampered crate, polluted dist, CRLF lock parsing.scripts/release/mpl-sources.mjsagainst crates.io: the five MPL crates (cssparser,cssparser-macros,dtoa-short,option-ext,selectors) downloaded and matchedCargo.lock.cargo test --lib: 136 passed. Clippy clean..apppassescodesign --verify --deep --strict(flags=adhoc,runtime);hdiutil verify, and the app inside it passes strict verification.tjs(GLIBC_2.38), including a fail case.lib.rsto CRLF and broke two source-scanning tests;.gitattributesnow forces LF;GLIBC_2.39, above the declared 2.38; the floor is now 2.39;.debis namedsq-lite-explorer, so the README's uninstall command was wrong.hdiutil verify; the app strict-verifies withadhoc,runtimeand has notices andtjsinside..deb: control file,libc6 (>= 2.39)covering theGLIBC_2.39its binaries need, description, notices andtjs.tjs.exeandquery-plan.dll; the app exe reports ProductName and FileVersion.assembleaccepted exactly the build jobs' asset names;shasum -c SHA256SUMSpasses for all six files;releasejob's own steps (attestation,gh release create --draft): not exercisable before a tag is pushed.