Releasing
August 26, 2026 · View on GitHub
Pushing a tag matching vX.Y.Z triggers .github/workflows/release.yml,
which builds the desktop app for macOS, Windows and Linux and publishes a GitHub Release with all
artifacts attached.
git tag v1.0.0
git push origin v1.0.0
This produces:
Fresh-install artifacts (what a user downloads from the Releases page the first time):
Condui-mac.dmg— signed and notarized universal (arm64 + amd64) buildCondui-windows-x64-installer.exe— NSIS installer (unsigned until SignPath is approved, see below)Condui-linux-x64.AppImage,Condui-linux-x64.deb,Condui-linux-x64.rpm
In-app updater artifacts (what an already-installed Condui downloads via Account → Check for Updates; see Updating below):
Condui-darwin-arm64-amd64.app.zip— the same signed/notarized.appbundle, zippedCondui-windows-amd64-update.exe— the bare.exe(no installer wrapper)Condui-linux-x64.AppImage— reused as-is; it's already a swappable single-file binarySHA256SUMS— digests the updater verifies downloads against
The public build includes ssh-gui/backend/dbexplorer (navoro) — now a public repo — checking out the
submodule recursively and building with the dbmanager Go build tag (EXTRA_TAGS: dbmanager on each
platform's build step) to enable the database explorer feature.
Updating
Condui embeds Wails v3's built-in updater
(github.com/wailsapp/wails/v3/pkg/updater, already vendored at the pinned go.mod version — no extra
dependency). ssh-gui/main.go wires it to the mgueregath/condui GitHub Releases API
(backend/buildconfig/build.config.yaml, key update_repo) with the release's SHA256SUMS as the
integrity check (github.Config.ChecksumAsset). The version compared against tag_name is baked in at
build time via -ldflags -X main.currentVersion=... (see the VERSION var in each
ssh-gui/build/{darwin,windows,linux}/Taskfile.yml, sourced from git describe --tags).
Users trigger a check from the Account modal ("Check for Updates…" — ssh-gui/app_update.go,
CheckForUpdates), which opens the framework's built-in update window: it shows the release notes,
downloads and verifies the matching asset, and swaps it in on Restart & Apply.
Why the updater needs its own assets instead of reusing the DMG/installer:
- The updater only knows how to unpack
.zip/.tar.gz(or take a bare file) before swapping — it can't mount a.dmgor invoke an NSIS installer. Hence the separate zipped.appand bare.exe. - The default asset matcher picks a release asset by
GOOS/GOARCHsubstring in the filename (darwin,windows,linux,amd64,arm64— withx64/x86_64/aarch64aliases). The macOS zip is named with both arch tokens since it's a universal binary that needs to match either host arch. - The AppImage needs no separate asset: it's already a bare, swappable single-file binary, and its
existing name (
Condui-linux-x64.AppImage) already contains matcher-recognized tokens (linux,x64as anamd64alias). .deb/.rpmhave no auto-update path here — package-manager artifacts aren't something this updater (or any equivalent without a hosted APT/YUM repo) can swap in place. Users on those tracks reinstall the new.deb/.rpmmanually, same as before this feature existed.- The NSIS installer,
.deband.rpmall contain the same platform/arch filename tokens as their corresponding update asset (e.g.Condui-windows-x64-installer.exeandCondui-windows-amd64-update.exeboth matchwindows+amd64), so the default matcher alone can't tell them apart — it just returns whichever comes first in the release's asset list.main.gowires a customAssetMatcher(updateAssetMatcher) that filters out anything withinstaller,.deb, or.rpmin the name before delegating togithub.DefaultAssetMatcher, so the updater can only ever pick a real update asset.
The Windows portable .exe ships unsigned for now, same as the installer (see SignPath section below) —
signing it requires a second SignPath Artifact Configuration once that's set up.
For stronger tamper-resistance than the SHA256SUMS digest check (integrity, not authenticity), the
Updater guide covers adding an Ed25519 signature (updater.Config.PublicKey + a signing step in CI) — not
wired up here; revisit if the distribution channel's trust model changes.
Required secrets (macOS signing & notarization)
Set these under Settings → Secrets and variables → Actions on the condui repo:
| Secret | Value |
|---|---|
MACOS_CERTIFICATE_P12 | base64 -i DeveloperIDApplication.p12 | pbcopy output of your exported Developer ID Application certificate |
MACOS_CERTIFICATE_PASSWORD | Password used when exporting the .p12 |
MACOS_KEYCHAIN_PASSWORD | Any password — only used to protect the throwaway CI keychain for the run |
MACOS_SIGN_IDENTITY | Exact identity string, e.g. Developer ID Application: Mirko Gueregat (TEAMID) |
APPLE_ID | Apple ID used for notarization |
APPLE_TEAM_ID | Apple Developer Team ID |
APPLE_APP_SPECIFIC_PASSWORD | App-specific password (generate at appleid.apple.com) for notarytool |
Without these, build-macos fails at the "Import signing certificate" step. Local ad-hoc releases via
scripts/release-macos.sh are unaffected — they keep using .env + the local keychain profile from
scripts/setup-macos-signing.sh.
Windows: applying for free code signing (SignPath Foundation)
The Windows installer currently ships unsigned. SignPath Foundation signs
open-source projects for free (no personal ID needed — they verify the binary was built from the public
condui repo instead). Steps to enable it:
- Apply at https://signpath.org/apply. Requirements: public repo, an existing automated build (this workflow now qualifies), and an actual release history — so it's worth doing an initial unsigned release first.
- Once approved, in the SignPath dashboard:
- Add GitHub.com as a Trusted Build System and link it to the
mgueregath/conduirepo/workflow. - Create a Project (e.g.
condui) and an Artifact Configuration describing the.exeto sign. - Create two Signing Policies:
test-signing(any branch, for validation) andrelease-signing(restricted to tag pushes / protected refs, used for real releases).
- Add GitHub.com as a Trusted Build System and link it to the
- Add these repo secrets:
SIGNPATH_API_TOKENSIGNPATH_ORGANIZATION_IDSIGNPATH_PROJECT_SLUGSIGNPATH_SIGNING_POLICY_SLUG
- That's it —
.github/workflows/release.ymlalready has the signing steps in thebuild-windowsjob, gated onsecrets.SIGNPATH_API_TOKEN != ''. As soon as the secrets exist, the next tagged release automatically submitsCondui-windows-x64-installer.exeto SignPath, waits for the signed artifact, and ships that instead of the unsigned one. No workflow changes needed.
Notes
ssh-gui/build/linux/nfpm/nfpm.yamlandssh-gui/build/windows/nsis/project.nsihad never been customized from the Wails scaffold defaults (testapp, "My Company") — this was fixed as part of setting up this pipeline so the Linux packages and Windows installer/product name now correctly say "Condui".- To test the pipeline without cutting a real release, push a tag to a fork or a throwaway
vX.Y.Z-rc1tag on a branch you don't mind deleting afterward — there's no manualworkflow_dispatchtrigger by design, only tag pushes.