Skip to content

build(release): add macOS notarization and Windows code signing#243

Merged
inureyes merged 1 commit into
mainfrom
update/issue-242-signing
May 26, 2026
Merged

build(release): add macOS notarization and Windows code signing#243
inureyes merged 1 commit into
mainfrom
update/issue-242-signing

Conversation

@inureyes

Copy link
Copy Markdown
Member

Summary

Brings the release pipeline to parity with backend.ai-go's packaging workflow so published artifacts are trusted by Gatekeeper and SmartScreen out of the box. All changes are confined to .github/workflows/release.yml.

macOS — added notarization after existing codesign

  • Submit a ditto'd zip of the already-codesigned binary to xcrun notarytool submit --wait using the App Store Connect API key (AC_API_KEY_ID / AC_API_ISSUER_ID / AC_API_PRIVATE_KEY_P8 secrets — already configured in the packaging environment but previously unused).
  • On Invalid/Rejected, fetch xcrun notarytool log <id> for diagnostics before failing the job.
  • Verify with spctl --assess --type execute --verbose; treat ticket-propagation lag as a warning (not a hard failure) since Gatekeeper checks online at first launch regardless.
  • Stapling is intentionally skipped. xcrun stapler only operates on .app/.dmg/.pkg containers, not on bare Mach-O executables. The notarization ticket lives on Apple's servers and Gatekeeper fetches it online — no offline ticket is needed for a single-binary CLI.
  • API key file is written to $RUNNER_TEMP with chmod 600 and removed unconditionally via trap cleanup EXIT.

Windows — switched to self-hosted runner and added signtool

  • Matrix entry os changed from windows-latestwindows-on-macmini02-x64, the same self-hosted runner used by backend.ai-go. Certificate is already installed in the Windows Certificate Store on that runner.
  • Sign all-smi.exe with signtool sign /tr http://ts.ssl.com/ /td sha256 /fd sha256 /a before the Compress-Archive step so the released .zip contains the signed .exe.
  • Verify with signtool verify /pa (warn-only — verification can lag right after signing on the timestamp authority).
  • Pin CARGO_HOME / RUSTUP_HOME to C:\.cargo / C:\.rustup outside GITHUB_WORKSPACE so the registry survives workspace cleanup between jobs.
  • Skip the actions/cache step on this runner since the persistent paths already handle caching; keeping it would only mirror an empty ~/.cargo.

Out of scope (per #242)

  • No .pkg/.dmg installers for macOS (stays single-binary)
  • No MSI/NSIS for Windows
  • No changes to ci.yml (still runs on windows-latest)
  • No changes to Linux/Homebrew/Debian PPA pipelines
  • No source code changes

Test plan

This workflow only triggers on release: published and workflow_dispatch. Validation needs to happen on the next release or a manual dispatch:

  • Trigger via workflow_dispatch against a draft tag (or wait for the next published release) and confirm:
    • macOS job: Notarize macOS binary step runs to completion with status: Accepted and spctl --assess reports the binary is trusted
    • Windows job: schedules onto windows-on-macmini02-x64 (not GitHub-hosted), Sign Windows binary with signtool step exits 0, signed all-smi-windows-x86_64.zip is uploaded
    • No secret values appear in workflow logs (GitHub auto-masks, but spot-check)
  • After download:
    • On macOS: spctl --assess --verbose --type execute /path/to/all-smi reports accepted and Notarized Developer ID
    • On Windows: Get-AuthenticodeSignature .\all-smi.exe reports Valid with a non-expired timestamp
  • Confirm Cache cargo step is skipped on the Windows job and present on the others

Closes #242

Brings the release pipeline to parity with backend.ai-go's packaging
workflow so published artifacts are trusted by Gatekeeper and SmartScreen
out of the box.

macOS:
- After the existing codesign step, submit a ditto'd zip of the binary
  to `xcrun notarytool submit --wait` using the App Store Connect API
  key (AC_API_KEY_ID / AC_API_ISSUER_ID / AC_API_PRIVATE_KEY_P8 secrets
  already configured in the `packaging` environment).
- On Invalid/Rejected, fetch `notarytool log` for diagnostics before
  failing.
- Verify with `spctl --assess --type execute`; treat ticket-propagation
  lag as a warning, not a hard failure.
- Stapling is intentionally skipped — `xcrun stapler` only operates on
  .app/.dmg/.pkg containers, not on bare Mach-O executables. Gatekeeper
  verifies the ticket online at first launch instead.
- API key file is written to `$RUNNER_TEMP` with chmod 600 and removed
  unconditionally via `trap`.

Windows:
- Switch the matrix entry from `windows-latest` to the self-hosted
  `windows-on-macmini02-x64` runner that already hosts the signing
  certificate in its Windows Certificate Store (same runner used by
  backend.ai-go).
- Sign all-smi.exe with `signtool sign /tr http://ts.ssl.com/
  /td sha256 /fd sha256 /a` before the `Compress-Archive` step so the
  released zip contains the signed binary.
- Verify with `signtool verify /pa` (warn-only on transient verification
  failure).
- Pin CARGO_HOME / RUSTUP_HOME to persistent paths outside
  GITHUB_WORKSPACE so the registry survives workspace cleanup; skip
  the actions/cache step on this runner since the persistent paths
  already handle it.

Closes #242
@inureyes inureyes added priority:high High priority issue status:review Under review type:chore Maintenance tasks (build, CI, etc) labels May 26, 2026
@inureyes inureyes merged commit 6c4f217 into main May 26, 2026
4 checks passed
@inureyes inureyes deleted the update/issue-242-signing branch May 26, 2026 16:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority:high High priority issue status:review Under review type:chore Maintenance tasks (build, CI, etc)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

build(release): add macOS notarization and Windows code signing

1 participant