Consolidate Authenticode, Apple notary, VM C, and digest-paste into platform/windows/wix/OPERATOR-READY.md (runbook + commands + secret names only). Cross-link from CI-SIGN-NOTARY, VM-C-ONE-PAGER, PACKAGING, and COMMERCIAL-INSTALLER-BACKLOG. Live enable remains blocked only on org secret store / clean VM — no secret values invented.
9.2 KiB
OPERATOR-READY — commercial MSI / notary / dual-ship
Status: software + dry-runs complete. Live sign / notary / VM C / CDN digests are READY: blocked only on org secret/VM (no missing in-repo steps).
Audience: release operator with org secret-store + clean Windows VM access.
Does not invent secrets. Names only. Values stay in org CI / keychain / operator home.
| Item | Blocker | In-repo ready |
|---|---|---|
| Org Authenticode / Trusted Signing | Org secret store values | Yes — names + example workflow + dry-run |
| Live Apple notary submit/staple | Apple API key / keychain profile | Yes — names + checklist + dry-run |
Clean VM C after enable-printer-cas |
Physical/clean VM sign-off | Yes — one-pager + dual-ship smoke |
| Real sha256 in DOWNLOADS-MANIFEST | Signed blobs on CDN first | Yes — hash helper + paste runbook |
Canonical siblings: CI-SIGN-NOTARY.md · VM-C-ONE-PAGER.md ·
DUAL-SHIP.md · VM-DUAL-SHIP-CHECKLIST.md ·
docs/PUBLISH-DIGESTS.md ·
platform/macos/menubar/NOTARIZE-CHECKLIST.md ·
.github/workflows/windows-msi-sign.yml.example ·
platform/macos/menubar/ci-notarize.yml.example
0) Preconditions (already in repo)
# From PrintToVeraeTimeStamp repo root
go test ./internal/pdfcert ./internal/statuslang -count=1
./platform/smoke-packaging-metadata.sh
./platform/macos/menubar/notary-dry-run.sh # exit 0; no submit
# Windows builder:
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\sign-dry-run.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\dual-ship-smoke.ps1
Unsigned MSI CI is live: .github/workflows/windows-msi.yml.
Sign/notary jobs stay gated (if: false) until secrets exist.
1) Org CI secrets — Authenticode / Trusted Signing
READY: blocked only on org secret/VM
Secret / var names (never commit values)
| Name | Kind | Purpose |
|---|---|---|
WINDOWS_CERT_PFX_BASE64 |
secret | Base64 PFX for Path A (signtool) |
WINDOWS_CERT_PFX_PASSWORD |
secret | PFX password |
WINDOWS_CERT_THUMBPRINT |
secret | Optional /sha1 after import |
WINDOWS_SIGN_TIMESTAMP_URL |
var | RFC 3161 TSA (e.g. https://timestamp.digicert.com) |
WINDOWS_TRUSTED_SIGNING_TENANT_ID |
secret | Path B Azure Trusted Signing |
WINDOWS_TRUSTED_SIGNING_CLIENT_ID |
secret | Path B |
WINDOWS_TRUSTED_SIGNING_CLIENT_SECRET |
secret | Omit when OIDC id-token: write |
WINDOWS_TRUSTED_SIGNING_ENDPOINT |
var | e.g. https://cus.codesigning.azure.net |
WINDOWS_TRUSTED_SIGNING_ACCOUNT |
var | Trusted Signing account name |
WINDOWS_TRUSTED_SIGNING_CERTIFICATE_PROFILE |
var | Certificate profile name |
Operator commands
# A) Add the names above to org GitHub/Forgejo secret store (values out-of-band).
# B) Copy example → live workflow (same secret names on Forgejo):
cp .github/workflows/windows-msi-sign.yml.example .github/workflows/windows-msi-sign.yml
# — or .forgejo/workflows/windows-msi-sign.yml with your Windows runs-on label
# C) Flip job gate: if: false → if: true (only after secrets exist)
# D) workflow_dispatch; download signed MSI artifact
# E) Local verify (Windows SDK):
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\sign-dry-run.ps1 `
-Path .\path\to\signed.msi
Do not claim SmartScreen reputation until clean-VM install proof.
Do not upload PFX as a workflow artifact.
2) Live notary submit / staple (macOS)
READY: blocked only on org secret/VM
Secret / env names
| Name | Purpose |
|---|---|
APPLE_API_KEY_P8_BASE64 |
App Store Connect API key .p8 (base64; CI materialize only) |
APPLE_API_KEY_ID |
Key ID |
APPLE_API_ISSUER_ID |
Issuer UUID |
APPLE_TEAM_ID |
Team ID for identity selection |
APPLE_CODESIGN_IDENTITY |
Developer ID Application: … (TEAMID) |
APPLE_INSTALLER_IDENTITY |
Developer ID Installer: … (TEAMID) (product .pkg) |
NOTARY_KEYCHAIN_PROFILE |
Laptop profile (default print: verae-notary) |
NOTARY_KEY_PATH / NOTARY_KEY_ID / NOTARY_ISSUER_ID |
Checklist aliases after materialize |
Operator commands (menubar accessory)
# Dry-run first (always safe; no submit):
./platform/macos/menubar/notary-dry-run.sh
# Build unsigned → codesign → ditto → notarytool → staple
# (full steps: platform/macos/menubar/NOTARIZE-CHECKLIST.md)
./platform/macos/menubar/build-menubar-app.sh "$HOME/Applications/Verae Menubar.app"
# codesign with $APPLE_CODESIGN_IDENTITY + entitlements (see checklist)
ditto -c -k --keepParent "$APP" /tmp/VeraeMenubar.zip
xcrun notarytool submit /tmp/VeraeMenubar.zip \
--keychain-profile "${NOTARY_KEYCHAIN_PROFILE:-verae-notary}" --wait
# or API key: --key "$NOTARY_KEY_PATH" --key-id "$APPLE_API_KEY_ID" --issuer "$APPLE_API_ISSUER_ID"
xcrun stapler staple "$APP" && xcrun stapler validate "$APP"
spctl --assess --type execute -vv "$APP"
Product .pkg (already scripted)
# When operator signing.env / CI secrets present:
# platform/macos/pkg/build-pkg.sh (codesign + notarytool --wait + stapler)
CI enable
cp platform/macos/menubar/ci-notarize.yml.example .github/workflows/macos-menubar-notarize.yml
# Flip menubar-notarize job if: false → true only after Apple secrets exist.
Never set NOTARY_SUBMIT=1 in shared CI without secrets + intentional release.
3) Clean VM C sign-off (enable-printer-cas)
READY: blocked only on org secret/VM
Host (Windows builder) — unlock + rebuild
# From repo root
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\enable-printer-cas.ps1 -Status
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\enable-printer-cas.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\build-full-msi.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\dual-ship-smoke.ps1 -VerifyArtifacts
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\sign-dry-run.ps1
# Re-disable files-only tree when done authoring:
# enable-printer-cas.ps1 -Disable
Clean VM C (operator physical/VM)
Printable ticks: VM-DUAL-SHIP-CHECKLIST.md § VM C. Narrative: DUAL-SHIP.md. One-pager: VM-C-ONE-PAGER.md.
- Install elevated full MSI (default or
VERAE_SKIP_PRINTERS=0). - Confirm files under Program Files + IPP/
127.0.0.1:8631+ Verae Print Helper task. - One-page PDF stamp → receipt/CID ≠ jobId (hold is never evidence).
- Uninstall clean; parity with VM A (NSIS).
- Sign off checklist; keep NSIS primary until thin-NSIS exit A–D.
dual-ship-smoke.ps1 prints steps offline — it does not replace VM C sign-off.
4) Upload signed blobs → real sha256 in DOWNLOADS-MANIFEST
READY: blocked only on org secret/VM
Order (fail closed) — docs/PUBLISH-DIGESTS.md:
- Build NSIS +/or full MSI (
build-full-msi.ps1/windows-msi.yml). - Sign (section 1) when shipping Windows trust.
- Upload the same bytes to CDN under reserved 0.3.6 leaf names.
- Hash (no upload in script):
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\fill-manifest-sha256.ps1 `
-Path .\dist\VeraePrintStamp-windows-amd64-0.3.6-setup.exe,
.\platform\windows\wix\out\VeraePrintStamp-windows-amd64-0.3.6.msi `
-Format both
POSIX shape if no pwsh:
shasum -a 256 VeraePrintStamp-windows-amd64-0.3.6-setup.exe \
VeraePrintStamp-windows-amd64-0.3.6.msi
# lowercase hex; two spaces; leaf name
- Paste over
TBDinsite/printit.verae.ai/DOWNLOADS-MANIFEST.txt+.md. - Verify re-download from public URL matches pasted digest.
Do not paste digests for unsigned-only CI smoke MSIs into production rows.
Reserved 0.3.6 leaves:
| Leaf | Channel |
|---|---|
VeraePrintStamp-windows-amd64-0.3.6-setup.exe |
NSIS primary |
VeraePrintStamp-windows-arm64-0.3.6-setup.exe |
NSIS arm64 |
VeraePrintStamp-windows-amd64-0.3.6.msi |
Full MSI dual-ship |
VeraePrintStamp-windows-arm64-0.3.6.msi |
Full MSI arm64 |
verae-print-windows-amd64-0.3.6.exe |
Optional bare helper |
Quick enable checklist (operator)
- Org secrets set (names in §1 / §2) — values never in git
- Copy
windows-msi-sign.yml.example→ live; flipif: false - Copy
ci-notarize.yml.example→ live when Apple secrets exist; flip gate enable-printer-cas.ps1+build-full-msi.ps1on Windows builder- Clean VM C ticks (checklist) signed off
- CDN upload of signed 0.3.6 blobs
fill-manifest-sha256.ps1→ paste TBD → re-download verify
Until every box above is done by a human with secrets/VM, commercial claims stay: software-complete, READY: blocked only on org secret/VM.
License
UNLICENSED © Verae — operator runbook; not a redistributable binary.