This is an administrator / operations guide. End users don’t need to read this — they just download a signed installer from GitHub Releases. This document explains how the signing infrastructure is wired up and what credentials need to exist for signing to actually happen.
Why we sign
Every GAIA Agent UI release ships installers for Windows (NSIS.exe), macOS (DMG), and Linux (DEB + AppImage). On Windows and macOS, unsigned installers trigger scary OS warnings:
- Windows SmartScreen: “Windows protected your PC” — the user has to click More info → Run anyway
- macOS Gatekeeper: “GAIA Agent UI cannot be opened because the developer cannot be verified” — the user has to right-click → Open → Open
Architecture
| Platform | Signing service | Credential type | Cost |
|---|---|---|---|
| Windows | SignPath OSS Foundation | API token | Free for OSS |
| macOS | Apple Developer ID + notarytool | .p12 cert + Apple ID | $99/yr (Apple Developer Program) |
| Linux DEB | electron-builder GPG | GPG private key | Free |
| Linux AppImage | electron-builder GPG | GPG private key | Free |
Windows: SignPath setup
SignPath provides free Windows code signing for open-source projects via their Foundation tier. One-time setup, takes ~1 week for OSS approval.Step 1: Apply for SignPath OSS
- Go to https://signpath.io/solutions/open-source-community
- Click Apply for free signing
- Fill out the form pointing at
https://github.com/amd/gaia - Reference the GAIA project description and link to this docs page
- Wait ~1 week for the SignPath team to review and approve
Step 2: Configure the project in SignPath
After approval, SignPath gives you access to a project dashboard. Create:| Setting | Value |
|---|---|
| Project slug | gaia-agent-ui |
| Signing policy slug | release-signing |
| Artifact configuration slug | gaia-installer |
| Trusted build system | GitHub |
| Repository | amd/gaia |
| Workflow path | .github/workflows/build-installers.yml |
| Workflow name | Build Installers |
| Branch/tag pattern | refs/tags/v* |
| Approval mode | Automatic |
.signpath/policies/gaia.policy (checked into the repo for auditability).
Step 3: Add GitHub Action secrets
In theamd/gaia repository settings → Secrets and variables → Actions → New repository secret, add:
| Secret name | Value |
|---|---|
SIGNPATH_API_TOKEN | API token from SignPath dashboard |
SIGNPATH_ORG_ID | Your SignPath organization UUID |
build-installers.yml workflow’s signing step is gated on both secrets being present — until they’re both set, the workflow ships an unsigned NSIS installer and the troubleshooting guide tells users how to bypass SmartScreen.
Step 4: Test the integration
- Push a release candidate tag:
git tag v0.17.2-rc.1 && git push --tags - The
Build Installersworkflow runs - Watch for the Sign Windows installer (SignPath) step — it should now upload the
.exeto SignPath, wait for signing, and download the signed artifact back - Download the artifact and verify it’s signed:
macOS: Apple Developer ID setup
macOS signing uses Apple’s standard Developer ID + notarization flow viaelectron-builder and notarytool. Requires an Apple Developer Program membership ($99/yr).
Step 1: Apple Developer Program
If AMD doesn’t already have a Developer Program enrollment for the GAIA team:- Enroll at https://developer.apple.com/programs/enroll/
- Choose Organization (not individual)
- Provide AMD’s D-U-N-S number
- Wait for Apple to verify the organization
Step 2: Generate a Developer ID Application certificate
- Sign in to https://developer.apple.com/account/resources/certificates
- Click + → Developer ID Application
- Generate a CSR via Keychain Access
- Download the
.cerand double-click to install in Keychain - Export the private key + certificate as a
.p12file with a strong password - Base64-encode the
.p12for storage in GitHub Secrets:
Step 3: Create an app-specific password for notarization
- Sign in to https://appleid.apple.com
- Security → App-Specific Passwords → Generate
- Label it
gaia-agent-ui-notarize - Copy the password (you can’t view it again)
Step 4: Add GitHub Action secrets
In repository settings → Secrets and variables → Actions, add:| Secret name | Value |
|---|---|
CSC_LINK | Base64-encoded .p12 file from Step 2 |
CSC_KEY_PASSWORD | The password you set on the .p12 |
APPLE_ID | Apple Developer Program email |
APPLE_APP_SPECIFIC_PASSWORD | App-specific password from Step 3 |
APPLE_TEAM_ID | 10-character team ID from Apple Developer dashboard |
build-installers.yml workflow auto-detects these via if: env.APPLE_ID != ''. Until they’re set, the workflow ships an unsigned .dmg and the troubleshooting guide tells users how to bypass Gatekeeper.
Step 5: Enable notarization
Insrc/gaia/apps/webui/electron-builder.yml, change:
notarize is true (or unset) and the Apple credentials are present, electron-builder will:
- Sign the
.appbundle - Create the
.dmg - Upload to Apple’s notarization service
- Wait for notarization to complete (usually < 5 minutes)
- Staple the notarization ticket to the
.dmg
Step 6: Test the integration
- Push a release candidate tag
- Watch the macOS job — look for
notarytool historyand the staple step - Download the signed
.dmg - Verify it’s signed and notarized:
Linux: GPG signing
electron-builder signs .deb packages with a GPG key automatically. The Linux runner needs:
| Secret name | Value |
|---|---|
GPG_PRIVATE_KEY | ASCII-armored private key block |
GPG_KEY_PASSPHRASE | Passphrase for the key |
appimagetool --sign. Same key works for both.
Troubleshooting
”SignPath approval is taking forever”
The OSS approval queue is sometimes 1–2 weeks. Don’t block release on it — ship unsigned, have the troubleshooting guide ready, and backfill signing when approval comes through. The unsigned.exe works; users just see the SmartScreen warning.
”macOS notarization fails on every build”
Check the notarization log:- Hardened runtime entitlements wrong — verify
installer/macos/entitlements.mac.plisthas all 5 entitlements (jit, allow-unsigned-executable-memory, disable-library-validation, allow-dyld-environment-variables, inherit). Without these, the notarized.appwill install but crash on first launch when it tries to spawnuv. - Helper apps not signed — Electron’s framework helpers must be signed too; electron-builder handles this automatically but it can fail if the
.p12is missing intermediate certificates. - Apple Developer ID expired — they expire every 5 years. Re-generate and re-upload to GitHub Secrets.
”I need to revoke a signing key”
For SignPath: contact SignPath support to invalidate the project token. The next build will produce an unsigned installer. For Apple Developer ID: revoke the cert in the Apple Developer dashboard. Existing notarized.dmgs remain valid because notarization tickets are stapled at build time, but new builds will fail until you generate a new cert.
”Can I test signing locally?”
Yes for macOS — if you have a Developer ID cert in your local Keychain, electron-builder picks it up automatically when you runnpm run package:mac locally. Set notarize: false in electron-builder.yml for local builds (notarization requires the credentials).
For Windows, SignPath’s OSS tier is GitHub-only — you can’t sign locally. Use unsigned local builds for development and let CI sign release tags.
References
- SignPath OSS Foundation: https://signpath.io/solutions/open-source-community
- SignPath GitHub Action: https://github.com/signpath/github-action-submit-signing-request
- Apple notarization docs: https://developer.apple.com/documentation/security/notarizing_macos_software_before_distribution
- electron-builder code signing: https://www.electron.build/code-signing
- GAIA desktop installer plan:
docs/plans/desktop-installer.mdx