Prints notarytool recipe with secret env names; links CI and backlog.
10 KiB
CI — Authenticode (Windows) + notarytool (macOS)
Status: unsigned MSI CI is live (.github/workflows/windows-msi.yml); sign/notary steps remain draft. No secrets in git.
Audience: release engineers wiring GitHub Actions or Forgejo Actions.
Related: Product-Full.wxs, SILENT_PROPS.md,
DUAL-SHIP.md § CI artifact,
.github/workflows/windows-msi.yml,
docs/COMMERCIAL-INSTALLER-BACKLOG.md,
platform/windows/scripts/sign-dry-run.ps1 — local signtool verify + print real sign commands (no secrets; exit 0 if no signtool),
platform/macos/menubar/notary-dry-run.sh — local notarytool recipe / tip (no secrets; submit only if NOTARY_SUBMIT=1),
platform/macos/menubar/ci-notarize.yml.example,
platform/macos/menubar/NOTARIZE-CHECKLIST.md,
platform/macos/pkg/build-pkg.sh.
Do not commit PFX, passwords, App Store Connect .p8, or real Team IDs used as secrets.
All credential names below are environment / secret store keys only.
Goals
| Artifact | Sign | Notarize / trust |
|---|---|---|
verae-print.exe, verae-printhelper.exe |
Authenticode (signtool) |
SmartScreen reputation over time |
| Full / tray MSI | Authenticode on the .msi |
Same |
macOS .pkg / menubar .app |
Developer ID | notarytool + stapler |
Primary product install remains NSIS until Product-Full.wxs lights + signs cleanly.
macOS pkg path already supports notary when operator SIGNING_ENV is set; CI should mirror that with secret injection.
Secret / env names (placeholders)
Windows Authenticode
| Env name | Purpose |
|---|---|
WINDOWS_CERT_PFX_BASE64 |
Base64 of code-signing PFX (CI import only) |
WINDOWS_CERT_PFX_PASSWORD |
PFX password |
WINDOWS_CERT_THUMBPRINT |
Optional: thumbprint when cert is pre-installed on runner |
WINDOWS_SIGN_TIMESTAMP_URL |
RFC 3161 TSA URL (e.g. DigiCert / Sectigo public TSA) |
WINDOWS_TRUSTED_SIGNING_* |
Optional Azure Trusted Signing — if used, prefer over PFX |
Never echo these values in logs. Prefer OIDC → cloud KMS/Trusted Signing when available.
Apple notary + Developer ID
| Env name | Purpose |
|---|---|
APPLE_API_KEY_P8_BASE64 |
App Store Connect API key .p8 (base64) |
APPLE_API_KEY_ID |
Key ID |
APPLE_API_ISSUER_ID |
Issuer UUID |
APPLE_TEAM_ID |
Team ID for codesign identity selection |
APPLE_CODESIGN_IDENTITY |
e.g. Developer ID Application: … (TEAMID) |
APPLE_INSTALLER_IDENTITY |
e.g. Developer ID Installer: … (TEAMID) |
NOTARY_KEYCHAIN_PROFILE |
Optional laptop path name (verae-notary); CI usually uses API key trio above |
Match names already used in operator signing.env where possible; map in the workflow, do not rename product scripts casually.
GitHub Actions sketch (Windows MSI + sign)
# .github/workflows/windows-msi-sign.yml — DRAFT, not enabled
name: windows-msi-sign
on:
workflow_dispatch:
# push:
# tags: ["printstamp-v*"]
jobs:
msi:
runs-on: windows-latest
permissions:
contents: read
# id-token: write # if using Azure OIDC Trusted Signing
steps:
- uses: actions/checkout@v4
- uses: actions/setup-go@v5
with:
go-version-file: apps/PrintToVeraeTimeStamp/go.mod
# adjust path if workflow lives inside the app repo root
- name: Build Windows binaries
shell: pwsh
working-directory: apps/PrintToVeraeTimeStamp # or repo root
run: |
# Prefer existing build-windows.ps1 / cross-build; stage under platform/windows/wix/StageFull
# go build → StageFull\bin\verae-print.exe + verae-printhelper.exe
# copy scripts + LICENSE + README-WINDOWS.txt into StageFull
Write-Host "TODO: wire build-windows.ps1 staging for Product-Full.wxs"
- name: Install WiX toolset
shell: pwsh
run: |
# choco install wixtoolset --version 3.14.x OR use preinstalled image
Write-Host "TODO: ensure candle/light on PATH"
- name: candle + light Product-Full
shell: pwsh
run: |
# candle -dProductVersion=… -dStageDir=… Product-Full.wxs
# light → out\VeraePrintStamp-windows-amd64-<ver>.msi
# Expect failure until StageFull complete — see Product-Full.wxs header
Write-Host "TODO: invoke candle/light"
- name: Import code-signing cert
shell: pwsh
env:
WINDOWS_CERT_PFX_BASE64: ${{ secrets.WINDOWS_CERT_PFX_BASE64 }}
WINDOWS_CERT_PFX_PASSWORD: ${{ secrets.WINDOWS_CERT_PFX_PASSWORD }}
run: |
# $bytes = [Convert]::FromBase64String($env:WINDOWS_CERT_PFX_BASE64)
# [IO.File]::WriteAllBytes("$env:RUNNER_TEMP\codesign.pfx", $bytes)
# Import-PfxCertificate -FilePath ... -CertStoreLocation Cert:\CurrentUser\My -Password ...
Write-Host "TODO: import PFX; never Upload-Artifact the PFX"
- name: signtool Authenticode
shell: cmd
env:
WINDOWS_SIGN_TIMESTAMP_URL: ${{ vars.WINDOWS_SIGN_TIMESTAMP_URL }}
run: |
REM signtool sign /fd SHA256 /tr %WINDOWS_SIGN_TIMESTAMP_URL% /td SHA256 /a ^
REM path\to\verae-print.exe path\to\verae-printhelper.exe path\to\*.msi
echo TODO: signtool after binaries + MSI exist
- name: Checksums
shell: pwsh
run: |
# Get-FileHash … SHA256 | Out-File SHA256SUMS
Write-Host "TODO: publish MSI + SHA256SUMS as release assets"
Forgejo Actions: same steps; replace ${{ secrets.* }} with Forgejo secret syntax (secrets.WINDOWS_CERT_PFX_BASE64, etc.) and runs-on with your Windows label. Keep secret names identical so docs stay portable.
GitHub Actions sketch (macOS notary)
# .github/workflows/macos-notarize.yml — DRAFT, not enabled
name: macos-notarize
on:
workflow_dispatch:
jobs:
notarize:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4
- name: Materialize notary API key
env:
APPLE_API_KEY_P8_BASE64: ${{ secrets.APPLE_API_KEY_P8_BASE64 }}
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
run: |
# mkdir -p "$RUNNER_TEMP/private_keys"
# echo "$APPLE_API_KEY_P8_BASE64" | base64 -d > "$RUNNER_TEMP/private_keys/AuthKey_${APPLE_API_KEY_ID}.p8"
# chmod 600 ...
echo "TODO: write .p8 outside workspace; delete in always() step"
- name: Codesign + pkgbuild path
env:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }}
APPLE_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
APPLE_INSTALLER_IDENTITY: ${{ secrets.APPLE_INSTALLER_IDENTITY }}
# NOTARY_KEY_PATH / KEY_ID / ISSUER_ID as expected by build-pkg.sh
run: |
# Prefer platform/macos/pkg/build-pkg.sh with SIGNING_ENV generated from secrets
# or menubar NOTARIZE-CHECKLIST.md steps for accessory .app
echo "TODO: call build-pkg.sh; notarytool submit --wait; stapler staple"
- name: Gatekeeper smoke (signed host only)
run: |
# spctl --assess --type install -vv path/to.pkg || true
# xcrun stapler validate path/to.pkg
echo "TODO: fail job on assess failure once pipeline is real"
Menubar-only accessory: follow NOTARIZE-CHECKLIST.md (ditto zip → notarytool → staple app).
GHA/Forgejo copy-paste sketch (unsigned default, notary job gated off): ci-notarize.yml.example.
Ordering (recommended)
- Build unsigned artifacts on CI (MSI light needs StageFull; pkg can already build unsigned).
- Sign Windows PE + MSI with
signtool(or Trusted Signing). - Notarize macOS zip/pkg with
notarytool --wait. - Staple macOS artifacts;
stapler validate. - Checksum + upload release assets; update
site/printit.verae.ai/DOWNLOADS-MANIFEST.txtout-of-band (platform/windows/scripts/fill-manifest-sha256.ps1prints rows only — does not upload) or via a docs job. - Never upload raw PFX /
.p8as workflow artifacts.
What is live vs what this draft does not do
Live: .github/workflows/windows-msi.yml builds an unsigned full MSI when WiX is installed on windows-latest and uploads the artifact (see DUAL-SHIP § CI artifact).
Local dry-run (no CI secrets):
- Windows:
../scripts/sign-dry-run.ps1findssigntool, runsverify /paon local MSI/EXE when present, and prints copy-pastesigntool signlines using the env names above only. Missing signtool → exit 0 + Windows SDK tip. Does not sign or import a PFX. - macOS menubar:
../../macos/menubar/notary-dry-run.shfindsnotarytool, prints codesign/ditto/submit/staple recipe (env names only), linksci-notarize.yml.example+COMMERCIAL-INSTALLER-BACKLOG.md. Missing notarytool → exit 0 + Xcode CLT tip. Never submits unlessNOTARY_SUBMIT=1.
Not done:
- Enable Authenticode
signtool/ Trusted Signing in that workflow (commented; secret names only). - Provide real certs, Team IDs, or TSA URLs.
- Replace NSIS as primary Windows download.
- Automate menubar notarization inside
build-menubar-app.sh(still checklist + backlog). - Claim SmartScreen reputation or Gatekeeper green without clean-VM proof.
License
UNLICENSED © Verae — CI sketch only; not a redistributable binary.