Prints checklist steps; -VerifyArtifacts uses fill-manifest-sha256.
16 KiB
Dual-ship runbook — NSIS + full MSI (side-by-side)
Status: operator validation while NSIS remains the primary full-product Windows download and the elevated MSI (Product-Full.wxs + build-full-msi.ps1) is unsigned and not yet CA-complete.
Do not thin or deprecate NSIS until the thin-NSIS exit criteria checklist (below) is fully checked — clean-VM gates, live Authenticode, silent/fleet proof, and site cutover (see COMMERCIAL-INSTALLER-BACKLOG.md, CI-SIGN-NOTARY.md).
Related: Product-Full.wxs · SILENT_PROPS.md · VM-DUAL-SHIP-CHECKLIST.md (printable A/B/C) · dual-ship-smoke.ps1 (offline checklist runner + optional local MSI/NSIS hash) · ../installer-windows.nsi · PACKAGING.md · site DOWNLOADS-MANIFEST.md (0.3.6 TBD rows) · fill-manifest-sha256.ps1 (hash built MSI/NSIS → manifest row; no upload).
Why dual-ship
| Channel | Role today | Gap vs commercial |
|---|---|---|
NSIS VeraePrintStamp-windows-*-setup.exe |
Primary GUI install (printers, helper task, key wizard, ARP) | Not MSI; Authenticode still open |
Full MSI VeraePrintStamp-windows-*-<ver>.msi |
Fleet path authoring (msiexec /qn props) |
Printer deferred CAs commented; unsigned; not Intune-proven |
Tray MSI VeraeTray-*-peruser.msi |
Optional non-elevated presence only | Not full product; distinct UpgradeCode |
Dual-ship means both NSIS and full MSI may be built from the same HelperVersion tree and validated on separate clean VMs without uninstalling the other channel’s install mid-test (use two VMs or one channel per VM).
Version rule
- Source of truth:
internal/job.HelperVersion(currently 0.3.6). - NSIS,
build-full-msi.ps1, and site product strings must stamp that value (or explicitVERSION=). - Site
DOWNLOADS-MANIFEST.txtmay still list last-published artifact filenames (historical checksums). Do not rewrite checksum lines until new binaries are published.
Build both artifacts (same tree)
From repo root on a Windows host with Go + NSIS + WiX v3 (candle/light) on PATH:
# 1) Native binaries + NSIS setup.exe
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\build-windows.ps1
# 2) Elevated full MSI (StageFull → candle/light)
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\build-full-msi.ps1
Expected outputs (names vary by arch):
| Artifact | Typical path |
|---|---|
| NSIS setup | dist/ or build output VeraePrintStamp-windows-amd64-<ver>-setup.exe |
| Full MSI | platform/windows/wix/out/VeraePrintStamp-windows-amd64-<ver>.msi |
Local SHA-256 for site manifest rows (no upload):
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\fill-manifest-sha256.ps1 `
-Path .\dist\VeraePrintStamp-windows-amd64-<ver>-setup.exe,
.\platform\windows\wix\out\VeraePrintStamp-windows-amd64-<ver>.msi
Paste printed digests over TBD in DOWNLOADS-MANIFEST.txt only after the blob is on the CDN. See DOWNLOADS-MANIFEST.md.
If WiX is missing, build-full-msi.ps1 exits 1 with an install tip — dual-ship fails closed for the MSI leg (do not claim MSI ready).
Cross-host NSIS-only: platform/windows/build-installer.sh (needs prebuilt Windows binaries).
Manifest checksum rows (no upload)
After artifacts exist locally (and only after they are on the CDN when rewriting site TBD):
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\fill-manifest-sha256.ps1 `
-Path .\dist\VeraePrintStamp-windows-amd64-<ver>-setup.exe,
.\platform\windows\wix\out\VeraePrintStamp-windows-amd64-<ver>.msi
Prints DOWNLOADS-MANIFEST.txt lines (<sha256> <leaf>). -Format md prints Markdown table rows for DOWNLOADS-MANIFEST.md. Does not upload or edit the site files.
Clean-VM matrix (minimum)
Printable tick sheet: VM-DUAL-SHIP-CHECKLIST.md (shared pre-checks + VM A/B/C steps + side-by-side table).
Offline checklist runner (prints the same A/B/C steps; optional local artifact existence + hash via fill-manifest — does not install or drive a VM):
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\dual-ship-smoke.ps1
powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\dual-ship-smoke.ps1 -VerifyArtifacts
Use two fresh Windows 10/11 x64 VMs (or reset snapshots). Do not mix channels on one machine until Upgrade/ARP coexistence is explicitly tested.
| VM | Install | Goal |
|---|---|---|
| A — NSIS primary | setup.exe (GUI) | Baseline product parity |
| B — MSI files-only | MSI with VERAE_SKIP_PRINTERS=1 |
File + ARP path without deferred printer CA |
| C — MSI printers (when CAs uncommented) | MSI default / VERAE_SKIP_PRINTERS=0 |
Printer + helper parity with NSIS |
Until printer CAs are scheduled and tested, treat VM C as blocked; dual-ship gate for “MSI can replace NSIS” stays open.
Shared pre-checks
- Snapshot or sysprep-clean OS; admin account available.
- Note
HelperVersionon both artifacts (NSIS version resource / MSIProductVersion). - No prior Verae Print Stamp under Program Files or ARP.
- Spooler running (
Get-Service Spooler).
VM A — NSIS validation
1. Run setup.exe elevated; complete key wizard or skip per test plan.
2. Confirm Program Files\Verae\PrintStamp\bin\verae-print.exe + helper.
3. Confirm printers (IPP and/or Local Port) and scheduled task "Verae Print Helper".
4. Print a one-page PDF → stamp path succeeds (or hold id only — never treat jobId as evidence).
5. Start Menu: Setup signing key, Start print helper, Collect diagnostics.
6. Uninstall via ARP; confirm printers/task removed; reboot optional.
Record: install log path, printer names, task principal, any SmartScreen blocks (unsigned expected).
VM B — MSI files-only (safe today)
Printer deferred CAs are commented in Product-Full.wxs. Validate payload + silent props without expecting queues:
msiexec /i VeraePrintStamp-windows-amd64-0.3.6.msi /qn /norestart ^
VERAE_SKIP_KEY_SETUP=1 VERAE_SKIP_PRINTERS=1 VERAE_CHANNEL=zapier
Interactive UI install is fine for smoke; /qn proves fleet syntax (SILENT_PROPS.md).
1. msiexec as above (or UI).
2. Confirm InstallDir files: bin\, scripts\ (incl. install-printer.ps1), LICENSE, README.
3. Confirm ARP entry (Publisher Verae, DisplayVersion = HelperVersion).
4. Confirm Start Menu shortcuts resolve to helper / diag (may fail if helper missing — fail the build).
5. Optional: elevated manual run of scripts\install-printer.ps1 -InstallDir "…" to prove script parity outside MSI CA.
6. msiexec /x {ProductCode} /qn — files and Start Menu removed; no orphan HKLM Software\Verae\PrintStamp if components clean.
Pass criteria (files-only): light-built MSI installs/uninstalls cleanly; version matches; no reboot required; props accepted (even if not yet honored by CAs).
Fail: missing StageFull binaries at light time; wrong UpgradeCode collision with tray MSI; elevation refused unexpectedly.
VM C — MSI printer CA (still left)
When uncommenting CAs in Product-Full.wxs:
- Schedule stubs (see commented
InstallExecuteSequencein Product-Full) afterInstallFiles. - Conditions:
NOT InstalledandVERAE_SKIP_PRINTERS<>"1"for install;REMOVE~="ALL"for uninstall. - Deferred elevated:
install-printer.ps1 -InstallDir "[INSTALLFOLDER]"; rollback/uninstall →uninstall-printer.ps1. - Re-run dual-ship A vs C parity: same printers, same helper task name, same IPP loopback
127.0.0.1:8631. - Silent:
VERAE_SKIP_PRINTERS=1must skip CA; default must install printers.
Do not mark dual-ship complete until VM C matches VM A on a clean image.
Side-by-side comparison checklist
| Check | NSIS (A) | MSI files (B) | MSI+CA (C) |
|---|---|---|---|
| Version = HelperVersion | ☐ | ☐ | ☐ |
| Program Files layout | ☐ | ☐ | ☐ |
| Start Menu shortcuts | ☐ | ☐ | ☐ |
| ARP uninstall clean | ☐ | ☐ | ☐ |
| IPP + Local Port printers | ☐ | N/A (skip) | ☐ |
| Scheduled task helper | ☐ | N/A (skip) | ☐ |
| Key wizard / first-run key | ☐ | skip prop | ☐ / first-run |
msiexec /qn |
N/A | ☐ | ☐ |
| Authenticode (signtool) | ☐ still left | ☐ still left | ☐ still left |
Coexistence / upgrade notes
- Full MSI UpgradeCode
F8B2A4C6-…must stay distinct from trayA7C3E91B-…. - NSIS uses its own
UNINST_KEY; long-term migrate ARP to MSI only after dual-ship pass — avoid dual ARP entries for the “same” product on one machine in production. - Do not install tray per-user MSI and full MSI as substitutes for each other; tray is presence-only.
- MajorUpgrade on full MSI: same-version upgrades allowed (
AllowSameVersionUpgrades=yes); test repair after dual-ship CA enablement.
Exit: when to thin NSIS (MSI becomes primary)
Thin or demote NSIS to “key-wizard offline only” (or drop from primary download) only when every box below is checked. Partial passes do not promote MSI. Until then: ship NSIS as primary; MSI is dual-ship candidate only.
Thin-NSIS exit criteria checklist
A — Product parity (clean VMs)
- VM A NSIS baseline signed off (files, printers, helper task, key path, ARP uninstall).
- VM B MSI files-only (
VERAE_SKIP_PRINTERS=1) install/uninstall clean; version =HelperVersion. - VM C MSI with printer/helper deferred CAs uncommented, scheduled, and tested — parity with VM A:
- Same Program Files layout (
bin\,scripts\, docs). - IPP loopback
127.0.0.1:8631and/or Local Port printers match NSIS names/behavior. - Scheduled task Verae Print Helper (same principal / trigger class).
- Start Menu shortcuts resolve; one-page PDF stamp path works (receipt/CID evidence — never jobId alone).
VERAE_SKIP_PRINTERS=1skips CAs; default installs printers.- Uninstall (
msiexec /x) removes printers, task, files, Start Menu; no orphan HKLMSoftware\Verae\PrintStamp.
- Same Program Files layout (
- Side-by-side comparison table (this doc) fully checked for columns A and C.
- Repair / same-version upgrade (
AllowSameVersionUpgrades) smoke on MSI after CA enablement.
B — Trust / signing
- Live Authenticode on
verae-print.exe,verae-printhelper.exe, and full.msi(CI or release host). - CI sign step enabled only with org secrets — never PFX/passwords in git (names in CI-SIGN-NOTARY.md /
windows-msi.ymlcomments). - SmartScreen: signed install path validated on a clean VM (warn-only unsigned is not enough to promote).
- Timestamp counter-signature present (
WINDOWS_SIGN_TIMESTAMP_URL/ equivalent TSA).
C — Fleet / silent contract
- Public silent props in SILENT_PROPS.md honored by scheduled CAs (not docs-only):
VERAE_SKIP_PRINTERS,VERAE_SKIP_KEY_SETUP, channel / API URL props as authored.
msiexec /qn /norestartone-liner documented with real exit codes from clean-VM runs.- Intune and/or SCCM sample deployment recorded (success + known failure codes); no reboot required for default path unless documented.
- UpgradeCode stays distinct from tray MSI; no dual “same product” ARP entries in production guidance.
D — Channel / site cutover
- Site primary Windows download points at signed full MSI (
VeraePrintStamp-windows-*-<ver>.msi). - NSIS
setup.exelinked as alternate only (or removed from primary CTA) — not the default button. DOWNLOADS-MANIFEST.txtchecksums refreshed for the promoted MSI (and remaining NSIS if kept) — usefill-manifest-sha256.ps1after upload (script does not upload).- Release notes / PACKAGING state MSI as primary full-product Windows install.
- OPEN-ISSUES Issue 1 Still left no longer lists dual-ship gate / thin-NSIS / “NSIS still primary”.
E — Explicit non-goals until checked
Do not thin NSIS if any of these remain true:
- Printer CAs still commented or untested (VM C blocked).
- CI only uploads unsigned MSI (
VeraePrintStamp-windows-msi-unsigned). - Operators still need NSIS for key wizard with no MSI-equivalent first-run path.
- Tray per-user MSI is being mistaken for full-product MSI.
When all of A–D are checked: demote NSIS (thin installer or archive-only), keep dual-ship docs as historical validation, and treat full MSI as the commercial Windows path.
CI artifact (unsigned full MSI)
GitHub Actions workflow .github/workflows/windows-msi.yml builds the elevated full MSI on windows-latest when WiX v3 (candle/light) is available:
- Checkout + Setup Go (
go-version-file: go.mod). - Install WiX Toolset v3 (Chocolatey) and put
candle/lightonPATH. - Run
platform/windows/scripts/build-full-msi.ps1 -Arch amd64(StageFull → candle/light). - Upload unsigned artifact
VeraePrintStamp-windows-msi-unsigned(platform/windows/wix/out/VeraePrintStamp-windows-*.msi).
| Fact | Detail |
|---|---|
| Trigger | workflow_dispatch; push/PR on Windows packaging + Go paths |
| Signed? | No — artifact is dual-ship candidate only; SmartScreen will warn |
| Use for | Clean-VM B (files-only) smoke; CI proof that authoring lights |
| Not for | Production download, Intune primary, or “MSI replaces NSIS” claims |
Future sign step (names only — not enabled): org secrets/vars documented in the workflow comments and CI-SIGN-NOTARY.md:
| Name | Kind |
|---|---|
WINDOWS_CERT_PFX_BASE64 |
secret |
WINDOWS_CERT_PFX_PASSWORD |
secret |
WINDOWS_CERT_THUMBPRINT |
secret (optional) |
WINDOWS_SIGN_TIMESTAMP_URL |
var |
WINDOWS_TRUSTED_SIGNING_* |
secret (optional Azure path) |
Do not put PFX bytes or passwords in git. Do not upload the PFX as a workflow artifact. Until sign is live, treat CI MSI like a local build-full-msi.ps1 output for dual-ship gates only.
Quick links
| Doc | Path |
|---|---|
| Full MSI authoring | Product-Full.wxs |
| Stage/light driver | ../scripts/build-full-msi.ps1 |
| CI unsigned MSI workflow | ../../../.github/workflows/windows-msi.yml |
| Silent properties | SILENT_PROPS.md |
| Printable VM A/B/C checklist | VM-DUAL-SHIP-CHECKLIST.md |
| Offline dual-ship smoke (print + optional hash) | ../scripts/dual-ship-smoke.ps1 |
| Sign/notary draft | CI-SIGN-NOTARY.md |
| Menubar CI notary example | ../../macos/menubar/ci-notarize.yml.example |
| Site 0.3.6 placeholders | DOWNLOADS-MANIFEST.md · DOWNLOADS-MANIFEST.txt |
| Local SHA-256 → manifest rows | ../scripts/fill-manifest-sha256.ps1 (hash only; no upload) |
| Commercial backlog | docs/COMMERCIAL-INSTALLER-BACKLOG.md |