This repository publishes desktop releases from Git tags via GitHub Actions.
- Final release:
vMAJOR.MINOR.PATCH(example:v1.2.3) - Pre-release:
vMAJOR.MINOR.PATCH-<prerelease>(example:v1.2.3-rc.1,v0.1.0-beta.11) - Accepted prerelease token format: dot-separated
[0-9A-Za-z-]+parts.
Validation regex in workflow:
^v([0-9]+)\.([0-9]+)\.([0-9]+)(-([0-9A-Za-z-]+(\.[0-9A-Za-z-]+)*))?$
Rules:
- If the tag has no suffix (
v1.2.3), GitHub release is published as final (prerelease: false). - If the tag contains a suffix (
v1.2.3-beta.1,v1.2.3-rc.1, ...), GitHub release is published as prerelease (prerelease: true).
Workflow file: .github/workflows/release.yml
Trigger:
- Push tag matching
v*
Pipeline order:
- Validate tag — SemVer format and prerelease flag.
- Test (Ubuntu only) —
npm test(Vitest) andcargo testinapps/desktop/src-tauri. If this job fails, no platform builds or GitHub release are produced. - Build matrix — only runs after tests pass.
Build matrix:
ubuntu-latestmacos-latestwindows-latest
For each platform:
- Checkout repository.
- Setup Node.js and Rust toolchain.
- Install Linux build dependencies (Linux only).
- Install npm dependencies (
apps/desktop). - Sync app version from tag into:
apps/desktop/package.jsonapps/desktop/src-tauri/tauri.conf.jsonapps/desktop/src-tauri/Cargo.toml- (Not rewritten by CI — keep in sync locally when you prepare a release PR:
apps/desktop/package-lock.jsontop-levelversionfields, andapps/desktop/src-tauri/Cargo.lock[[package]] name = "src-tauri"version line.)
- Run
npm run tauri:buildwith optionalNOSUCKSHELL_LICENSE_PUBKEY_HEX(64 hex chars) in the environment so the binary embeds your production Ed25519 verify key at compile time (option_env!inapps/desktop/src-tauri/src/license.rs). - Upload generated bundles as build artifacts.
For official release binaries, configure a repository secret:
- Name:
NOSUCKSHELL_LICENSE_PUBKEY_HEX - Value: 64-character hex string (32-byte Ed25519 public key) matching your deployed
LICENSE_SIGNING_SEED_HEX.
The release workflow passes this secret into the Tauri build step. If the secret is missing (for example on a fork), builds still succeed but use the development verify key—fine for experimentation, not for selling tokens to end users.
Local release-style build:
export NOSUCKSHELL_LICENSE_PUBKEY_HEX="<your-64-hex-public-key>"
cd apps/desktop && npm run tauri:buildRelease job:
- Download all uploaded platform artifacts.
- Create GitHub release for the tag.
- Mark release as final/prerelease based on parsed tag.
- Attach all built artifacts to the release.
When a GitHub Release is published (not only tag push), .github/workflows/aur-publish.yml can update the AUR package nosuckshell-bin using aur/nosuckshell-bin/PKGBUILD. It runs only on the upstream repository d0dg3r/NoSuckShell and requires the AUR_SSH_PRIVATE_KEY repository secret (SSH key with push access to the AUR). See aur/README.md for one-time setup.
Create and push a tag:
# final release
git tag v0.2.0
git push origin v0.2.0
# prerelease
git tag v0.3.0-rc.1
git push origin v0.3.0-rc.1
# stable release (example: current product line)
git tag v0.2.1
git push origin v0.2.1-
Target tag:
v0.3.5— push when you are ready; in-repo versions inapps/desktop/package.json,apps/desktop/package-lock.json,apps/desktop/src-tauri/tauri.conf.json, andapps/desktop/src-tauri/Cargo.tomlmust match before you tag (see CHANGELOG.md). -
What ships: see CHANGELOG.md for
0.3.5. -
The release workflow still overwrites those files from the tag at build time; keeping them in sync avoids drift before the tag lands.
-
Working-tree drift: if
package.jsonis bumped ahead ofCargo.toml/tauri.conf.json(or the reverse), realign before you cut a release so localtauri devand CI agree on the product version.
- Ensure workflow has
permissions: contents: write(required for release upload). - Ensure Linux runner installs Tauri system dependencies.
- Keep version source single: tag is the source of truth.
- Use tag-based trigger only (avoid releasing on every commit).
- Keep asset names/platform artifacts separated by matrix job.
- Keep workflow
concurrencyenabled to prevent duplicate runs for the same tag.
Current workflow builds and publishes unsigned artifacts. For production distribution, add platform signing:
- Windows:
- Sign
.exe/.msiwith a trusted code-signing certificate. - Store certificate material and passwords in GitHub Secrets.
- Sign
- macOS:
- Sign app with Apple Developer ID certificate.
- Notarize with Apple notary service.
- Staple notarization ticket to distributables (
.app/.dmg).
- Linux:
- AppImage generally works unsigned, but optional signature/provenance can be added in a hardened pipeline.
Some rolling distros ship libgit2 that expects a version-tagged libpcre2 from the system. The AppImage bundles its own libpcre2 under the mount (/tmp/.mount_*/usr/lib/...). If anything in your environment puts that mount on the library search path while a host binary loads /usr/lib/libgit2.so.*, the dynamic linker can mix host libgit2 + AppImage libpcre2, which triggers warnings such as:
no version information available (required by /usr/lib/libgit2.so.*)
Typical triggers:
LD_LIBRARY_PATH(or similar) still containing the AppImage mount in a shell where you run git-aware tools (for exampleeza/exa/lsdaliased asll).- Running those tools in the same environment while the AppImage payload is mounted.
Mitigations:
- Prefer the native Arch package (
.pkg.tar.zstfrom CI) on Arch-based systems when you hit this; it avoids AppImage library injection. - Use a clean shell without AppImage paths in
LD_LIBRARY_PATHfor unrelated CLI tools. - Official release AppImages are post-processed in CI to remove bundled
libpcre2-8so the loader can pick the systemlibpcre2that matches your distro’slibgit2(seescripts/postprocess-linux-appimage-libs.sh).
Recommended next step:
- Add secrets for signing credentials.
- Add conditional signing steps in
.github/workflows/release.yml. - Verify signed artifacts on each platform before public rollout.