Commercial installer backlog (MSI + notarized macOS .app)
Backlog for shipping-grade installers: a full Windows MSI and a codesigned + notarized macOS .app (and related distribution). This is inventory of what already exists versus what is still missing.
Day-to-day packaging (tray, menu bar, version stamps, CERT-01, IPP GET vs POST) is documented in PACKAGING.md. This file does not replace that runbook; it tracks commercial distribution gaps only.
Product version source of truth: internal/job.HelperVersion (see PACKAGING.md § Version source of truth). All commercial artifacts must stamp that value (or an explicit VERSION= override), not hard-coded older defaults.
Scaffold shipped (this leftover)
Repo now includes authoring/docs scaffolds for the two commercial gaps that were still empty trees. These are not shipping-grade release artifacts.
| Scaffold |
Path |
What it is |
What it is not |
| WiX tray presence MSI skeleton |
platform/windows/wix/ — VeraeTrayShortcuts.wxs, VeraeTrayShortcutsFragment.wxs, README.md; driver scripts/build-tray-msi.ps1 |
Non-elevated per-user WiX v3 product + shortcut fragment: stages verae-tray.ps1, Start Menu Programs\Verae\Verae Tray.lnk, Startup Verae Tray.lnk. ProductVersion wired from Get-VeraePackageVersion → internal/job.HelperVersion (or VERSION= / -Version). build-tray-msi.ps1 runs candle/light when present; otherwise prints WiX install tip (exit 0). |
Full elevated commercial MSI (printers, Program Files, Authenticode, NSIS parity, CI-signed MSI in dist/). No MSI binary without the WiX toolset on the build host. |
| Menubar notarize checklist |
platform/macos/menubar/NOTARIZE-CHECKLIST.md |
Operator step list: unsigned build → codesign hardened runtime → ditto zip → notarytool (keychain profile or API key placeholders) → staple → spctl. No secrets. |
Automated sign/notarize in build-menubar-app.sh, stapled .app.zip/DMG release, or live CI keychain import. |
| Menubar CI notary sketch |
platform/macos/menubar/ci-notarize.yml.example |
GHA/Forgejo example workflow: default unsigned build-menubar-app.sh + artifact; commented notarytool job gated if: false; secret names only (APPLE_API_KEY_*, APPLE_CODESIGN_IDENTITY, …). |
Not a live workflow under .github/; no staple; not Gatekeeper-proven. |
| Full elevated MSI (StageFull + light) |
Product-Full.wxs + scripts/build-full-msi.ps1 (+ outline, SILENT_PROPS.md, CI-SIGN-NOTARY.md, DUAL-SHIP.md) |
Elevated WiX v3 product: perMachine, Feature/ComponentGroups for bin (verae-print.exe required), scripts, docs, Start Menu; silent public props; distinct UpgradeCode. build-full-msi.ps1 creates StageFull/{bin,scripts}, copies or Go-builds EXEs, copies scripts/LICENSE/README, stamps ProductVersion from Get-VeraePackageVersion, runs candle/light → VeraePrintStamp-windows-*-<version>.msi. WiX missing → exit 1 + clear tip. Version defaults on build-windows / build-pkg / NSIS / build-installer aligned to HelperVersion. Commented deferred CA + InstallExecuteSequence stubs for install-printer.ps1 (no binaries required). Dual-ship runbook documents NSIS vs MSI clean-VM gates + thin-NSIS exit checklist. |
Not Authenticode-signed; printer CAs still commented (not scheduled/tested); properties not yet honored by live CAs; not Intune-proven; NSIS still primary full install; CI builds unsigned MSI only (sign step not live). |
| CI unsigned full MSI |
.github/workflows/windows-msi.yml + DUAL-SHIP § CI artifact |
windows-latest: install WiX v3 → build-full-msi.ps1 → upload artifact VeraePrintStamp-windows-msi-unsigned. Future Authenticode secret names only in workflow comments / CI-SIGN-NOTARY. |
No live signtool; no certs in git; not a production download channel. |
Issue 1 — what landed vs still open
| Done (advanced) |
Still left (Issue 1 commercial) |
Product-Full.wxs File components match StageFull; candle/light-ready |
Uncomment + test printer deferred CAs on clean VM (DUAL-SHIP VM C); parity with NSIS |
build-full-msi.ps1 StageFull + ProductVersion + exit codes |
Live CI: signtool / Trusted Signing on MSI + EXEs (workflow sign step commented; secret names only) |
CI-SIGN-NOTARY.md GHA/Forgejo draft (secret names only) |
Live notarytool staple on macOS runners; clean-VM Gatekeeper proof |
SILENT_PROPS.md msiexec one-liner + exit codes for full MSI |
Properties honored by scheduled CAs (config write, skip printers/key) |
| HelperVersion path on build-windows / build-pkg / NSIS / build-installer / full MSI |
Dual-ship clean-VM validation (A/B/C); then execute thin-NSIS exit checklist |
Commented CA + InstallExecuteSequence stubs (install-printer schedule) |
Intune/SCCM silent smoke with real exit codes; publish 0.3.6 signed blobs + manifest checksums |
DUAL-SHIP.md NSIS+MSI + CI artifact + thin-NSIS exit checklist |
Site primary download still NSIS; thin/demote NSIS only after exit checklist A–D |
| Site product string → 0.3.6; manifest header notes HelperVersion vs last-published 0.3.2 |
Do not claim Authenticode / notary / dual-ship / thin-NSIS complete |
.github/workflows/windows-msi.yml unsigned MSI on windows-latest + artifact upload |
Wire org secrets and enable sign step; publish signed assets to site |
ci-notarize.yml.example menubar GHA/Forgejo sketch (unsigned default; secret names) |
Promote example → live workflow; automate build-menubar-app.sh sign when SIGNING_ENV set |
Still use for day-to-day presence (no WiX / no Apple certs):
Windows scripts/build-tray-startmenu.ps1 + install-tray-startup.ps1; macOS verae-print menubar --install / unsigned build-menubar-app.sh. Full product install remains NSIS (installer-windows.nsi) and macOS pkg/build-pkg.sh. Optional: build-tray-msi.ps1 (WiX tip exit 0); build-full-msi.ps1 (needs WiX; exit 1 if missing).
Goals (definition of done)
| Platform |
Ship artifact |
Done when |
| Windows |
Elevated MSI (WiX or equivalent) + Authenticode-signed payload |
Enterprise deployable via Intune/SCCM/GPO; silent install; upgrade/uninstall ARP; printer + helper + tray; signed binaries and MSI |
| macOS |
Developer ID codesigned, notarized, stapled .app (and/or signed .pkg that installs it) |
Gatekeeper clean on fresh Mac (spctl assess pass); hardened runtime; no right-click Open workaround; version = HelperVersion |
Related but out of scope for “done” above (still backlog-adjacent): Linux .deb, auto-update channels, MSIX / Print Support App.
Windows — full MSI
Exists today
NSIS product already covers much of the install experience (files under Program Files, key setup UI, IPP + Local Port printers, helper task, Start Menu, uninstall, diagnostics). That is not an MSI and is not WiX-based.
Missing for commercial MSI
| Gap |
Why it matters |
Suggested work |
| Full-product WiX authoring + StageFull driver |
Exists — Product-Full.wxs + build-full-msi.ps1 |
MSI binary only on hosts with candle/light; still dual-ship NSIS |
| MSI output when WiX present |
wix/out/VeraePrintStamp-windows-<arch>-<version>.msi via build-full-msi.ps1 |
Not yet published to dist/ / site downloads; no SHA256 release job |
| No Authenticode signing pipeline in-repo |
SmartScreen / enterprise trust |
signtool (or Azure Trusted Signing) for EXE/DLL and MSI; store certs in CI secrets only — never in git. Not shipped. |
| Silent / unattended install contract |
Fleet deploy |
Props documented (SILENT_PROPS.md); wire scheduled CAs to honor them |
| Upgrade / repair / ARP metadata |
Clean major-upgrade, Add/Remove Programs |
WiX UpgradeCode present; migrate ARP fully from NSIS UNINST_KEY after dual-ship |
| Custom actions parity with NSIS |
Printers, scheduled helper, per-user key |
Port install-printer.ps1, helper registration into deferred/impersonated CAs (stubs commented in Product-Full) |
| Per-user vs per-machine story |
Tray is user-level today; MSI is typically machine |
Machine full MSI + optional per-user tray MSI (both authored; product decision open) |
| Version drift in build scripts |
Largely fixed — HelperVersion path on build-windows, build-full-msi, build-pkg, build-installer, NSIS fallbacks 0.3.6; site index product string 0.3.6 |
Keep smoke failing on new hard-coded older defaults; DOWNLOADS-MANIFEST still checksums last-published 0.3.2 blobs until release upload |
| CI job that builds + signs MSI |
Reproducible release |
Unsigned build live (.github/workflows/windows-msi.yml); signtool / Trusted Signing still not live (secret names only) |
| MSIX / Print Support App (later) |
Modern print path in original spec |
Explicitly deferred unless enterprise asks; not blocking first MSI |
Windows backlog order (suggested)
Freeze install surface / WiX file components + StageFull driver (done: outline + Product-Full + build-full-msi.ps1).
Dual-ship runbook + commented printer CA schedule stubs (done: DUAL-SHIP.md; Product-Full commented InstallExecuteSequence).
CI unsigned full MSI workflow + artifact (done: .github/workflows/windows-msi.yml; DUAL-SHIP § CI artifact).
- Uncomment + test printer/helper deferred CAs on clean VM (DUAL-SHIP VM C); keep NSIS primary until parity.
- Authenticode on binaries + MSI (not shipped — enable commented sign step; secret names in workflow +
CI-SIGN-NOTARY.md).
- Honor silent props in live CAs + Intune sample command line proof.
- Publish 0.3.6 artifacts; refresh site
DOWNLOADS-MANIFEST checksums; keep smoke on HelperVersion drift.
- Deprecate or thin NSIS once MSI is the primary download (thin-NSIS exit checklist A–D in DUAL-SHIP.md — all boxes).
macOS — notarized .app (and signed .pkg)
Exists today
| Item |
Location / notes |
Status |
Signed + notarized .pkg builder |
platform/macos/pkg/build-pkg.sh |
Full commercial path for installer package: universal verae-print, codesign hardened runtime, stages Verae Print Stamp.app, pkgbuild + productbuild (Developer ID Installer), notarytool submit --wait, stapler staple, SHA256SUMS |
| Entitlements |
platform/macos/pkg/entitlements.plist |
network client, user-selected files, allow-jit |
| Postinstall (printer, LaunchAgent, key setup) |
platform/macos/pkg/scripts/postinstall |
Console-user IPP queue + mac-key-setup |
| App bundle inside pkg stage |
Built by build-pkg.sh → /Applications/Verae Print Stamp.app |
Thin wrapper: runs verae-print mac-key-setup or stamp -open on dropped PDFs; codesigned in pkg flow |
| Signing env (external) |
$HOME/fie/installers/macos/signing.env (default); not in repo |
API key path / issuer / Developer ID identities — correct secret hygiene |
| IPP LaunchAgent + install scripts |
platform/macos/ipp/ |
Used by pkg postinstall |
| Menu bar Swift + LaunchAgent |
platform/macos/menubar/ |
Runtime presence; see PACKAGING.md § macOS menu bar |
Unsigned menu-bar .app builder |
platform/macos/menubar/build-menubar-app.sh |
Dev/local only; copies entitlements but does not codesign |
| Notarization documentation only (menubar) |
platform/macos/menubar/README.txt + PACKAGING.md § Codesign + notarization |
Manual steps; no automated menubar notarize |
| Notarize checklist (menubar) |
platform/macos/menubar/NOTARIZE-CHECKLIST.md |
Scaffold shipped — notarytool placeholders, staple, spctl; no secrets; automation still open |
| Packaging smoke |
platform/smoke-packaging-metadata.sh |
Version + “no elevated MSI” + IPP purity — not Gatekeeper |
Missing for commercial notarized .app
| Gap |
Why it matters |
Suggested work |
No first-class standalone notarized .app zip/DMG release |
Many users expect drag-to-Applications .app, not only .pkg |
After codesign: ditto zip or DMG → notarytool → staple app (and DMG if used); publish VeraePrintStamp-<version>.app.zip / .dmg + SHA256 |
Menu-bar .app not in automated sign/notarize path |
PT-06 presence still unsigned by default |
Extend build-menubar-app.sh (or share a sign-and-notarize.sh) to apply Developer ID + notarytool + staple when SIGNING_ENV is set; keep unsigned default for dev |
Product .app is a thin launcher, not a full bundled helper |
App depends on files under /Library/Application Support/Verae/PrintStamp/ from the pkg |
Either (a) keep .pkg as primary and document that, or (b) ship a self-contained .app with embedded verae-print, registration-pdf, IPP assets, and first-run setup |
| Menubar not installed by pkg postinstall |
Users get printer + key setup but not menu bar unless they run verae-print menubar --install |
Optional: postinstall or app first-run installs LaunchAgent / offers menu-bar .app |
| Version default drift |
Fixed — build-pkg.sh greps HelperVersion (fallback 0.3.6) |
Keep smoke if pkg default ≠ HelperVersion; site manifest still lists older shipped pkgs |
| No DMG branding / layout (optional) |
Nicer download UX |
create-dmg or hdiutil with Applications symlink; notarize DMG |
| No Sparkle / appcast auto-update |
Commercial expectation for .app |
Deferred unless product asks; if added, EdDSA keys outside repo |
| Stapled artifact CI publish |
Repeatable Gatekeeper-clean builds |
macOS runner with custom keychain import of Developer ID + notary API key; upload stapled .pkg and optional .app.zip |
| Gatekeeper verification in smoke |
Catch regressions |
On signed hosts: spctl -a -vv -t install on .pkg, spctl --assess --type execute on .app, stapler validate |
| Hardened runtime audit of nested binaries |
Notary rejections |
Ensure registration-pdf node bits are not executed under hardened runtime incorrectly; only sign Mach-O helpers that actually run |
| Bundle ID / naming consistency |
Support and updates |
Pkg app: ai.verae.print-stamp; menubar: ai.verae.timestamping.menubar — document which is “the” commercial app vs accessory |
macOS backlog order (suggested)
Point build-pkg.sh VERSION at HelperVersion (done). Verify stapled .pkg on a clean VM (Gatekeeper + printer + key setup).
- Decide distribution primary:
.pkg only (already closest to done) vs self-contained notarized .app (+ optional DMG).
- If
.app primary: bundle helper + resources inside the app; first-run equals today’s postinstall responsibilities without root where possible.
- Automate menubar sign/notarize as accessory artifact (or embed menubar in product app) — not shipped as automated path.
- CI: promote
ci-notarize.yml.example → live notarize + staple + spctl + checksums; never commit signing.env.
- Optional: DMG, Sparkle.
Cross-platform commercial gaps
| Gap |
Notes |
| Single release checklist |
One version (HelperVersion), Windows MSI + setup.exe (transition), macOS stapled .pkg / .app, SHA256SUMS, site download links (site/printit.verae.ai/DOWNLOADS-MANIFEST.txt) |
| Secrets policy |
Already correct direction: no certs/passwords in git; Apple signing.env and Windows PFX/Trusted Signing only in CI or operator home |
| Install API / registration |
docs/installer-registration-api.md + internal/installapi — keep MSI/pkg silent props aligned |
| Channel / metering defaults |
PrintIt → zapier channel; document MSI/pkg property overrides |
| Hold ≠ evidence |
Tray/menubar must stay GET-only; commercial installers must not teach IPP POST from presence UI (PACKAGING.md § IPP) |
| Linux commercial |
platform/linux/deb/build-deb.sh exists; not part of MSI/app done criteria |
Quick status matrix
| Deliverable |
Exists |
Commercial-ready |
| Windows tray / Startup / Start Menu (user) |
Yes |
Yes for presence; not enterprise MSI |
Windows NSIS setup.exe |
Yes |
Partial — full GUI install; needs Authenticode + version align; not MSI |
| Windows MSI (WiX) tray presence skeleton |
Yes (.wxs + build-tray-msi.ps1; ProductVersion ← HelperVersion) |
No — scaffold only; MSI only when candle/light installed; not full product MSI |
| Windows MSI full product (files + ARP) |
Yes authoring (Product-Full.wxs + build-full-msi.ps1 StageFull → light; CA schedule stubs commented) |
No commercial — unsigned; printer CAs not live; NSIS still primary |
| Dual-ship NSIS↔MSI runbook |
Yes (DUAL-SHIP.md) |
Docs only — clean-VM validation + thin-NSIS exit checklist still unchecked |
| Menubar CI notary example |
Yes (ci-notarize.yml.example) |
Example only — unsigned default; notary job if: false |
| Windows Authenticode pipeline |
Draft doc (wix/CI-SIGN-NOTARY.md) |
No — no live signtool job (do not claim shipped) |
| macOS menu bar LaunchAgent |
Yes |
Yes (dev/ops) |
macOS unsigned menubar .app |
Yes |
No (Gatekeeper) |
macOS signed+notarized .pkg script |
Yes |
Near — needs version sync, CI, clean-VM proof |
macOS standalone notarized .app zip/DMG |
Partial (app built inside pkg only) |
No as primary download |
| Menubar notarize checklist |
Yes (NOTARIZE-CHECKLIST.md) |
Docs only — not automated |
| Menubar automated notarization |
Docs + checklist only |
No |
References
Maintenance
When closing a row above, update the Quick status matrix and add a one-line note under the relevant “Exists” table (path + date). When shipping a new scaffold (authoring only), add/refresh the Scaffold shipped section rather than marking commercial-ready. Do not move day-to-day tray/menubar how-to out of PACKAGING.md into this backlog.