PrintToVeraeTimeStamp/platform/windows/wix/CI-SIGN-NOTARY.md
George Lambert 3140e6c76f
Some checks failed
windows-msi / full-msi-unsigned (push) Has been cancelled
feat: PUBLISH-DIGESTS.md + commented Authenticode CI paths + EmbedBrandFonts TTF
windows-msi-sign.yml.example; gofpdf register when EmbedBrandFonts and fonts present.
2026-10-14 01:24:11 -04:00

8.2 KiB

CI — Authenticode (Windows) + notarytool (macOS)

Status: unsigned MSI CI is live (.github/workflows/windows-msi.yml); sign/notary steps remain draft (commented secret names + example workflow). 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 — unsigned build + commented signtool / Trusted Signing,
.github/workflows/windows-msi-sign.yml.example — full sign sketch (if: false; secret names only),
docs/PUBLISH-DIGESTS.md — fill DOWNLOADS-MANIFEST after sign via fill-manifest-sha256.ps1,
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)

Canonical example file: .github/workflows/windows-msi-sign.yml.example
(Path A: PFX + signtool; Path B: Azure Trusted Signing; job if: false; secret names only.)

Also mirrored as commented blocks in .github/workflows/windows-msi.yml under the unsigned job.

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.


  1. Build unsigned artifacts on CI (MSI light needs StageFull; pkg can already build unsigned).
  2. Sign Windows PE + MSI with signtool (or Trusted Signing).
  3. Notarize macOS zip/pkg with notarytool --wait.
  4. Staple macOS artifacts; stapler validate.
  5. Checksum + upload release assets; update site/printit.verae.ai/DOWNLOADS-MANIFEST.txt out-of-band — see docs/PUBLISH-DIGESTS.md (fill-manifest-sha256.ps1 prints rows only — does not upload).
  6. Never upload raw PFX / .p8 as 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):

Not done:

  • Enable Authenticode signtool / Trusted Signing (example + comments exist; live job still off).
  • 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.
  • Paste real 0.3.6 digests into DOWNLOADS-MANIFEST (runbook: PUBLISH-DIGESTS.md).

License

UNLICENSED © Verae — CI sketch only; not a redistributable binary.