Some checks failed
windows-msi / full-msi-unsigned (push) Has been cancelled
windows-msi-sign.yml.example; gofpdf register when EmbedBrandFonts and fonts present.
230 lines
31 KiB
Markdown
230 lines
31 KiB
Markdown
# 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](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](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/`](../platform/windows/wix/) — `VeraeTrayShortcuts.wxs`, `VeraeTrayShortcutsFragment.wxs`, [`README.md`](../platform/windows/wix/README.md); driver [`scripts/build-tray-msi.ps1`](../platform/windows/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`](../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`](../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. |
|
||
| **Menubar notary dry-run** | [`platform/macos/menubar/notary-dry-run.sh`](../platform/macos/menubar/notary-dry-run.sh) | Local helper: if `notarytool` present print codesign/`ditto`/submit/staple recipe with env **names** only; else Xcode CLT tip (exit 0). Links [`ci-notarize.yml.example`](../platform/macos/menubar/ci-notarize.yml.example) + this backlog. **Never submits** unless `NOTARY_SUBMIT=1`. | Not live CI; does not codesign by default; not Gatekeeper-proven. |
|
||
| **Full elevated MSI (StageFull + light)** | [`Product-Full.wxs`](../platform/windows/wix/Product-Full.wxs) + [`scripts/build-full-msi.ps1`](../platform/windows/scripts/build-full-msi.ps1) (+ outline, [`SILENT_PROPS.md`](../platform/windows/wix/SILENT_PROPS.md), [`CI-SIGN-NOTARY.md`](../platform/windows/wix/CI-SIGN-NOTARY.md), [`DUAL-SHIP.md`](../platform/windows/wix/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`](../.github/workflows/windows-msi.yml) + DUAL-SHIP § CI artifact | `windows-latest`: install WiX v3 → `build-full-msi.ps1` → upload artifact `VeraePrintStamp-windows-msi-unsigned`. Commented **signtool** + **Trusted Signing** steps (secret **names** only). | No live `signtool`; no certs in git; not a production download channel. |
|
||
| **CI sign example** | [`.github/workflows/windows-msi-sign.yml.example`](../.github/workflows/windows-msi-sign.yml.example) | GHA/Forgejo **example**: build + Path A PFX/`signtool` + Path B Azure Trusted Signing; all gated `if: false`; secret **names** only. | Not a live workflow; no certs; does not claim SmartScreen. |
|
||
| **Publish digests runbook** | [`docs/PUBLISH-DIGESTS.md`](PUBLISH-DIGESTS.md) | Operator order: build → sign → upload → `fill-manifest-sha256.ps1` → paste TBD. | Does not upload or enable live sign. |
|
||
|
||
### Issue 1 — what landed vs still open
|
||
|
||
| Done (advanced) | Still left (Issue 1 commercial) |
|
||
|-----------------|----------------------------------|
|
||
| `Product-Full.wxs` File components match StageFull; candle/light-ready | **Enable** (`enable-printer-cas.ps1`) **+ test** printer deferred CAs on clean VM (DUAL-SHIP VM C); parity with NSIS |
|
||
| `build-full-msi.ps1` StageFull + ProductVersion + exit codes | **Enable** live CI Authenticode: wire org secrets + flip `windows-msi-sign.yml.example` / uncomment `windows-msi.yml` sign steps |
|
||
| `CI-SIGN-NOTARY.md` GHA/Forgejo draft (secret **names** only) + [`sign-dry-run.ps1`](../platform/windows/scripts/sign-dry-run.ps1) local verify/print | Live CI **signtool** / Trusted Signing still **not** running; live notarytool staple on macOS; 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`](../platform/windows/wix/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`](../.github/workflows/windows-msi.yml) unsigned MSI + **commented** signtool / Trusted Signing (secret names) | Org secrets + enable sign; publish signed assets to site |
|
||
| [`windows-msi-sign.yml.example`](../.github/workflows/windows-msi-sign.yml.example) full sign sketch (`if: false`) | Promote example → live workflow when certs exist |
|
||
| [`ci-notarize.yml.example`](../platform/macos/menubar/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 |
|
||
| **0.3.6 Windows NSIS+MSI placeholder rows** ([`DOWNLOADS-MANIFEST.txt`](../site/printit.verae.ai/DOWNLOADS-MANIFEST.txt) + [`DOWNLOADS-MANIFEST.md`](../site/printit.verae.ai/DOWNLOADS-MANIFEST.md); sha256 **TBD**) | Build/upload signed 0.3.6 blobs; replace TBD with real digests |
|
||
| [`fill-manifest-sha256.ps1`](../platform/windows/scripts/fill-manifest-sha256.ps1) + [`PUBLISH-DIGESTS.md`](PUBLISH-DIGESTS.md) (hash → paste; **no upload**) | Operator still must upload first, then paste digests over TBD |
|
||
| **Printable VM A/B/C sheet** [`VM-DUAL-SHIP-CHECKLIST.md`](../platform/windows/wix/VM-DUAL-SHIP-CHECKLIST.md) | Operator sign-off on clean VMs (C blocked until CAs uncommented) |
|
||
| **Offline dual-ship smoke** [`dual-ship-smoke.ps1`](../platform/windows/scripts/dual-ship-smoke.ps1) (prints A/B/C; **VM C blocked until CAs enabled**; `-VerifyArtifacts` → existence + `fill-manifest-sha256.ps1`) | Does **not** replace clean-VM sign-off; no install/sign/upload |
|
||
| **Enable printer CAs** [`enable-printer-cas.ps1`](../platform/windows/scripts/enable-printer-cas.ps1) + wix README § Enable printer CAs | Unwraps `DEFERRED_PRINTER_CAS:OFF` in Product-Full for VM C; does **not** build/test/sign; default remains disabled |
|
||
| **Authenticode dry-run** [`sign-dry-run.ps1`](../platform/windows/scripts/sign-dry-run.ps1) + [`CI-SIGN-NOTARY.md`](../platform/windows/wix/CI-SIGN-NOTARY.md) | Local verify + print sign cmds only (**no secrets**). Live CI signtool / Trusted Signing still **not** enabled |
|
||
| **Notary dry-run** [`notary-dry-run.sh`](../platform/macos/menubar/notary-dry-run.sh) + [`ci-notarize.yml.example`](../platform/macos/menubar/ci-notarize.yml.example) | Local print submit recipe (env **names**); tip if no notarytool; submit only if `NOTARY_SUBMIT=1`. Live notary CI still **not** enabled |
|
||
|
||
**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
|
||
|
||
| Item | Location / notes | Status |
|
||
|------|------------------|--------|
|
||
| **NSIS GUI setup.exe** (elevated product install) | [`platform/windows/installer-windows.nsi`](../platform/windows/installer-windows.nsi) | **Shipped path** for full product (not MSI) |
|
||
| Older/simpler NSIS script | [`platform/windows/installer.nsi`](../platform/windows/installer.nsi) | Present; used by cross-build helper |
|
||
| Native Windows build → setup.exe | [`platform/windows/build-windows.ps1`](../platform/windows/build-windows.ps1) | Builds `verae-print.exe` + GUI helper, runs `makensis` |
|
||
| Cross-host NSIS build | [`platform/windows/build-installer.sh`](../platform/windows/build-installer.sh) | Needs prebuilt binaries from `scripts/build-win-linux.sh` |
|
||
| Printer install / uninstall | [`platform/windows/scripts/install-printer.ps1`](../platform/windows/scripts/install-printer.ps1), `uninstall-printer.ps1` | Used by NSIS product |
|
||
| Tray NotifyIcon + GET `/status` | [`platform/windows/scripts/verae-tray.ps1`](../platform/windows/scripts/verae-tray.ps1) | User-level; see [PACKAGING.md](PACKAGING.md) § Windows tray |
|
||
| Startup-folder tray install | [`platform/windows/scripts/install-tray-startup.ps1`](../platform/windows/scripts/install-tray-startup.ps1) | **Not** MSI; no elevation |
|
||
| WiX-free Start Menu stub | [`platform/windows/scripts/build-tray-startmenu.ps1`](../platform/windows/scripts/build-tray-startmenu.ps1) | Explicitly “future MSI can supersede” |
|
||
| **WiX tray presence skeleton** (per-user, non-elevated) | [`platform/windows/wix/`](../platform/windows/wix/) + [`scripts/build-tray-msi.ps1`](../platform/windows/scripts/build-tray-msi.ps1) | **Scaffold shipped** — ProductVersion ← HelperVersion; candle/light when present, else WiX tip; not full product MSI |
|
||
| **WiX full elevated MSI** (StageFull driver) | [`Product-Full.wxs`](../platform/windows/wix/Product-Full.wxs) + [`scripts/build-full-msi.ps1`](../platform/windows/scripts/build-full-msi.ps1) | **Authoring + stage/light path** — MSI when WiX present; unsigned; printer CAs commented stubs; dual-ship NSIS |
|
||
| **CI unsigned full MSI** | [`.github/workflows/windows-msi.yml`](../.github/workflows/windows-msi.yml) | **Live workflow** — WiX install → `build-full-msi.ps1` → unsigned artifact; sign step commented (secret names only) |
|
||
| **Dual-ship runbook** | [`wix/DUAL-SHIP.md`](../platform/windows/wix/DUAL-SHIP.md) | **Docs** — NSIS + MSI clean-VM matrix; CI artifact section; **thin-NSIS exit checklist** (A–E) |
|
||
| **Printable VM checklist** | [`wix/VM-DUAL-SHIP-CHECKLIST.md`](../platform/windows/wix/VM-DUAL-SHIP-CHECKLIST.md) | **Docs** — tick boxes for shared pre-checks + VM A/B/C + side-by-side |
|
||
| **0.3.6 download placeholders** | [`site/.../DOWNLOADS-MANIFEST.md`](../site/printit.verae.ai/DOWNLOADS-MANIFEST.md) + `.txt` TBD rows | **Docs** — NSIS setup + full MSI filenames reserved; digests TBD until publish |
|
||
| **Manifest SHA-256 row helper** | [`scripts/fill-manifest-sha256.ps1`](../platform/windows/scripts/fill-manifest-sha256.ps1) | **Tool** — local `Get-FileHash` → SHA256SUMS / MD rows; does **not** upload or rewrite site files |
|
||
| **Offline dual-ship smoke** | [`scripts/dual-ship-smoke.ps1`](../platform/windows/scripts/dual-ship-smoke.ps1) | **Tool** — prints VM A/B/C checklist; notes **C blocked until CAs enabled**; optional local MSI/NSIS existence + hash via fill-manifest; does **not** install or drive VMs |
|
||
| **Enable deferred printer CAs** | [`scripts/enable-printer-cas.ps1`](../platform/windows/scripts/enable-printer-cas.ps1) | **Tool** — toggles `DEFERRED_PRINTER_CAS:OFF` / `:ON` markers in Product-Full.wxs (VM C prereq); default disabled |
|
||
| **Authenticode dry-run** | [`scripts/sign-dry-run.ps1`](../platform/windows/scripts/sign-dry-run.ps1) | **Tool** — find `signtool`; verify unsigned MSI/EXE; print sign command templates (secret **names** only); exit 0 if no signtool; **does not sign** |
|
||
| Shared version helper | [`platform/windows/scripts/common.ps1`](../platform/windows/scripts/common.ps1) `Get-VeraePackageVersion` | Aligns tray/full MSI/NSIS drivers with `HelperVersion` |
|
||
| End-user Windows readme | [`platform/windows/README-WINDOWS.txt`](../platform/windows/README-WINDOWS.txt), [`README.txt`](../platform/windows/README.txt) | Documents NSIS flow; states **no elevated MSI** for tray |
|
||
| Packaging policy doc | [PACKAGING.md](PACKAGING.md) | “**No elevated MSI**” for tray presence by design |
|
||
| Spec intent (historical) | [`docs/superpowers/specs/2026-10-03-print-to-verae-timestamp.md`](superpowers/specs/2026-10-03-print-to-verae-timestamp.md) | Mentions MSI + Authenticode as product direction |
|
||
| Plan checkbox (open) | [`docs/superpowers/plans/2026-10-03-print-to-verae-timestamp.md`](superpowers/plans/2026-10-03-print-to-verae-timestamp.md) | “Tray helper build, WiX MSI, Authenticode signing” still unchecked |
|
||
|
||
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; local hash helper `fill-manifest-sha256.ps1` (no upload/CI publish job yet) |
|
||
| **No Authenticode signing pipeline** in-repo | SmartScreen / enterprise trust | Local dry-run: [`sign-dry-run.ps1`](../platform/windows/scripts/sign-dry-run.ps1). Live: `signtool` (or Azure Trusted Signing) for EXE/DLL **and** MSI; store certs in CI secrets only — never in git. **Live sign 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** (`windows-msi.yml`); sign **example** + commented Path A/B (`windows-msi-sign.yml.example`); signtool / Trusted Signing still **not live** |
|
||
| **MSIX / Print Support App** (later) | Modern print path in original spec | Explicitly **deferred** unless enterprise asks; not blocking first MSI |
|
||
|
||
### Windows backlog order (suggested)
|
||
|
||
1. ~~Freeze install surface / WiX file components + StageFull driver~~ (**done**: outline + Product-Full + `build-full-msi.ps1`).
|
||
2. ~~Dual-ship runbook + commented printer CA schedule stubs~~ (**done**: [`DUAL-SHIP.md`](../platform/windows/wix/DUAL-SHIP.md); Product-Full commented `InstallExecuteSequence`).
|
||
3. ~~CI unsigned full MSI workflow + artifact~~ (**done**: [`.github/workflows/windows-msi.yml`](../.github/workflows/windows-msi.yml); DUAL-SHIP § CI artifact).
|
||
4. **Enable** printer/helper deferred CAs (`enable-printer-cas.ps1`) + test on clean VM (DUAL-SHIP VM C); keep NSIS primary until parity. `dual-ship-smoke` blocks C until CAs enabled.
|
||
5. Authenticode on binaries + MSI (**not shipped** — enable [`windows-msi-sign.yml.example`](../.github/workflows/windows-msi-sign.yml.example) / commented steps in `windows-msi.yml`; secret names in `CI-SIGN-NOTARY.md`; local dry-run [`sign-dry-run.ps1`](../platform/windows/scripts/sign-dry-run.ps1)).
|
||
6. Honor silent props in live CAs + Intune sample command line proof.
|
||
7. Publish 0.3.6 artifacts; refresh site `DOWNLOADS-MANIFEST` per [`PUBLISH-DIGESTS.md`](PUBLISH-DIGESTS.md) + `fill-manifest-sha256.ps1` (hash-only; no upload); keep smoke on HelperVersion drift.
|
||
8. 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`](../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`](../platform/macos/pkg/entitlements.plist) | network client, user-selected files, allow-jit |
|
||
| Postinstall (printer, LaunchAgent, key setup) | [`platform/macos/pkg/scripts/postinstall`](../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/`](../platform/macos/ipp/) | Used by pkg postinstall |
|
||
| Menu bar Swift + LaunchAgent | [`platform/macos/menubar/`](../platform/macos/menubar/) | Runtime presence; see [PACKAGING.md](PACKAGING.md) § macOS menu bar |
|
||
| **Unsigned** menu-bar `.app` builder | [`platform/macos/menubar/build-menubar-app.sh`](../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`](../platform/macos/menubar/README.txt) + [PACKAGING.md](PACKAGING.md) § Codesign + notarization | Manual steps; no automated menubar notarize |
|
||
| **Notarize checklist** (menubar) | [`platform/macos/menubar/NOTARIZE-CHECKLIST.md`](../platform/macos/menubar/NOTARIZE-CHECKLIST.md) | **Scaffold shipped** — notarytool placeholders, staple, `spctl`; no secrets; automation still open |
|
||
| **Notary dry-run** (menubar) | [`platform/macos/menubar/notary-dry-run.sh`](../platform/macos/menubar/notary-dry-run.sh) | **Tool** — print submit recipe (env names) or Xcode tip; links `ci-notarize.yml.example` + this backlog; **no submit** unless `NOTARY_SUBMIT=1` |
|
||
| Packaging smoke | [`platform/smoke-packaging-metadata.sh`](../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)
|
||
|
||
1. ~~Point `build-pkg.sh` `VERSION` at `HelperVersion`~~ (**done**). Verify stapled `.pkg` on a clean VM (Gatekeeper + printer + key setup).
|
||
2. Decide distribution primary: **`.pkg` only** (already closest to done) vs **self-contained notarized `.app`** (+ optional DMG).
|
||
3. If `.app` primary: bundle helper + resources inside the app; first-run equals today’s postinstall responsibilities without root where possible.
|
||
4. Automate menubar sign/notarize as accessory artifact (or embed menubar in product app) — **not shipped** as automated path.
|
||
5. CI: promote [`ci-notarize.yml.example`](../platform/macos/menubar/ci-notarize.yml.example) → live notarize + staple + `spctl` + checksums; never commit `signing.env`.
|
||
6. 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`](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](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`](../platform/windows/wix/DUAL-SHIP.md)) | **Docs only** — clean-VM validation + thin-NSIS exit checklist still unchecked |
|
||
| Menubar CI notary example | **Yes** ([`ci-notarize.yml.example`](../platform/macos/menubar/ci-notarize.yml.example)) | **Example only** — unsigned default; notary job `if: false` |
|
||
| Menubar notary dry-run | **Yes** ([`notary-dry-run.sh`](../platform/macos/menubar/notary-dry-run.sh)) | **Scaffold** — print recipe / tip; submit gated `NOTARY_SUBMIT=1` only |
|
||
| Windows Authenticode pipeline | **Draft** (`wix/CI-SIGN-NOTARY.md`) + **dry-run** [`sign-dry-run.ps1`](../platform/windows/scripts/sign-dry-run.ps1) + commented steps in [`windows-msi.yml`](../.github/workflows/windows-msi.yml) + [`windows-msi-sign.yml.example`](../.github/workflows/windows-msi-sign.yml.example) | **No** — no live signtool job (**do not claim shipped**) |
|
||
| Publish digests runbook | **Yes** ([`PUBLISH-DIGESTS.md`](PUBLISH-DIGESTS.md) + `fill-manifest-sha256.ps1`) | **Docs/tool** — operator still uploads + pastes TBD |
|
||
| 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
|
||
|
||
- **[PACKAGING.md](PACKAGING.md)** — tray, menubar, unsigned `.app`, notarization steps (docs), CERT-01, statuslang, IPP split, smoke tests
|
||
- [`platform/windows/`](../platform/windows/) — NSIS + tray scripts
|
||
- [`platform/windows/wix/`](../platform/windows/wix/) + [`build-tray-msi.ps1`](../platform/windows/scripts/build-tray-msi.ps1) — per-user tray MSI skeleton; ProductVersion ← HelperVersion
|
||
- [`platform/windows/wix/Product-Full.wxs`](../platform/windows/wix/Product-Full.wxs) + [`build-full-msi.ps1`](../platform/windows/scripts/build-full-msi.ps1) — elevated full MSI StageFull + candle/light
|
||
- [`platform/windows/wix/DUAL-SHIP.md`](../platform/windows/wix/DUAL-SHIP.md) — NSIS + MSI side-by-side validation runbook
|
||
- [`platform/windows/wix/CI-SIGN-NOTARY.md`](../platform/windows/wix/CI-SIGN-NOTARY.md) — CI Authenticode + notarytool sketch (**draft only**)
|
||
- [`.github/workflows/windows-msi-sign.yml.example`](../.github/workflows/windows-msi-sign.yml.example) — GHA sign example (signtool + Trusted Signing; `if: false`; secret names only)
|
||
- [`docs/PUBLISH-DIGESTS.md`](PUBLISH-DIGESTS.md) — fill DOWNLOADS-MANIFEST after sign via `fill-manifest-sha256.ps1`
|
||
- [`platform/windows/scripts/sign-dry-run.ps1`](../platform/windows/scripts/sign-dry-run.ps1) — local `signtool` verify + print sign commands (no secrets; exit 0 if no signtool)
|
||
- [`platform/windows/wix/SILENT_PROPS.md`](../platform/windows/wix/SILENT_PROPS.md) — msiexec `/qn` property contract
|
||
- [`platform/macos/pkg/`](../platform/macos/pkg/) — commercial `.pkg` build
|
||
- [`platform/macos/menubar/`](../platform/macos/menubar/) — menu bar + unsigned `.app` + notarize docs/checklist
|
||
- [`platform/macos/menubar/NOTARIZE-CHECKLIST.md`](../platform/macos/menubar/NOTARIZE-CHECKLIST.md) — menubar notarytool step list
|
||
- [`platform/macos/menubar/ci-notarize.yml.example`](../platform/macos/menubar/ci-notarize.yml.example) — GHA/Forgejo menubar CI sketch (unsigned default; secret names only)
|
||
- [`platform/macos/menubar/notary-dry-run.sh`](../platform/macos/menubar/notary-dry-run.sh) — local notarytool dry-run (print recipe; `NOTARY_SUBMIT=1` to submit)
|
||
- [`docs/installer-registration-api.md`](installer-registration-api.md) — installer ↔ portal registration API
|
||
- [`README.md`](../README.md) — top-level packaging pointers
|
||
|
||
---
|
||
|
||
## 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](PACKAGING.md) into this backlog.
|