diff --git a/docs/COMMERCIAL-INSTALLER-BACKLOG.md b/docs/COMMERCIAL-INSTALLER-BACKLOG.md index 126cda2..f5a8cf2 100644 --- a/docs/COMMERCIAL-INSTALLER-BACKLOG.md +++ b/docs/COMMERCIAL-INSTALLER-BACKLOG.md @@ -24,7 +24,7 @@ Repo now includes **authoring/docs scaffolds** for the two commercial gaps that | 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 | +| `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 | 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) | @@ -37,7 +37,8 @@ Repo now includes **authoring/docs scaffolds** for the two commercial gaps that | **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) local hash → DOWNLOADS-MANIFEST rows (linked from DUAL-SHIP + manifest.md; **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; `-VerifyArtifacts` → existence + `fill-manifest-sha256.ps1`) | Does **not** replace clean-VM sign-off; no install/sign/upload | +| **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 | **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). @@ -76,7 +77,8 @@ Related but out of scope for “done” above (still backlog-adjacent): Linux `. | **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; optional local MSI/NSIS existence + hash via fill-manifest; does **not** install or drive VMs | +| **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 | | 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 | @@ -105,7 +107,7 @@ NSIS product already covers much of the *install experience* (files under Progra 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. **Uncomment** + test printer/helper deferred CAs on clean VM (DUAL-SHIP VM C); keep NSIS primary until parity. +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 commented sign step; secret names in workflow + `CI-SIGN-NOTARY.md`). 6. Honor silent props in live CAs + Intune sample command line proof. 7. Publish 0.3.6 artifacts; refresh site `DOWNLOADS-MANIFEST` checksums via `fill-manifest-sha256.ps1` (hash-only; no upload); keep smoke on HelperVersion drift. diff --git a/platform/windows/scripts/dual-ship-smoke.ps1 b/platform/windows/scripts/dual-ship-smoke.ps1 index c099f1d..af7b516 100644 --- a/platform/windows/scripts/dual-ship-smoke.ps1 +++ b/platform/windows/scripts/dual-ship-smoke.ps1 @@ -151,7 +151,39 @@ Write-Host ("HelperVersion expect: {0} arch: {1}" -f $Version, $Arch) Write-Host ("Repo: {0}" -f $RepoRoot) Write-Host "Docs: platform/windows/wix/DUAL-SHIP.md" Write-Host " platform/windows/wix/VM-DUAL-SHIP-CHECKLIST.md" -Write-Host "Rules: one channel per VM; receipt/CID only (never jobId-only); VM C blocked while printer CAs commented." +Write-Host "Rules: one channel per VM; receipt/CID only (never jobId-only)." + +# Detect deferred printer CA enablement in Product-Full.wxs (authoring gate for VM C). +$productFullWxs = Join-Path $WixDir "Product-Full.wxs" +$casState = "unknown" +$vmCBlocked = $true +if (Test-Path -LiteralPath $productFullWxs) { + $wxsText = [System.IO.File]::ReadAllText($productFullWxs) + $hasOff = $wxsText.Contains("") + $hasOn = $wxsText.Contains("") -and $wxsText.Contains("") + if ($hasOn -and -not $hasOff) { + $casState = "enabled" + $vmCBlocked = $false + } elseif ($hasOff -and -not $hasOn) { + $casState = "disabled" + $vmCBlocked = $true + } elseif ($wxsText -match 'CustomAction\s+Id="CA_InstallPrinters"' -and $wxsText -notmatch 'DEFERRED_PRINTER_CAS:OFF') { + # Markers absent but InstallPrinters CA appears live (manual enable). + $casState = "enabled-manual" + $vmCBlocked = $false + } else { + $casState = "disabled-or-missing" + $vmCBlocked = $true + } +} +if ($vmCBlocked) { + Write-Host ("VM C: BLOCKED until printer CAs enabled (Product-Full state: {0})." -f $casState) -ForegroundColor Yellow + Write-Host " Enable: platform\windows\scripts\enable-printer-cas.ps1 then rebuild MSI." -ForegroundColor DarkGray + Write-Host " Enabling authoring is NOT a dual-ship pass — clean-VM C still required." -ForegroundColor DarkGray +} else { + Write-Host ("VM C: CAs enabled in authoring ({0}) — still need rebuild + clean-VM parity vs A." -f $casState) -ForegroundColor Cyan + Write-Host " dual-ship gate stays open until VM C matches VM A (DUAL-SHIP.md)." -ForegroundColor DarkGray +} # --- Shared pre-checks --- Write-Section "Shared pre-checks (every VM)" @@ -188,8 +220,17 @@ Write-Note "Pass (files-only): clean install/uninstall; version match; props acc Write-Note "VM B sign-off: pass / fail · ProductCode · initials" # --- VM C --- -Write-Section "VM C — MSI printer CA (BLOCKED until CAs live)" -Write-Note "Prereq: uncomment + schedule deferred CAs in Product-Full.wxs; rebuild MSI." +if ($vmCBlocked) { + Write-Section "VM C — MSI printer CA (BLOCKED until CAs enabled)" + Write-Note ("Product-Full.wxs deferred CAs: {0}" -f $casState) + Write-Note "Prereq: enable-printer-cas.ps1 (or unwrap DEFERRED_PRINTER_CAS:OFF markers); rebuild MSI." + Write-Note "NOTE: VM C BLOCKED until CAs enabled — dual-ship gate stays open." +} else { + Write-Section "VM C — MSI printer CA (CAs enabled in authoring — clean-VM still left)" + Write-Note ("Product-Full.wxs deferred CAs: {0}" -f $casState) + Write-Note "Prereq done in tree; rebuild MSI if not yet rebuilt after enable." + Write-Note "NOTE: authoring enabled ≠ dual-ship pass (clean-VM C still required)." +} Write-Step "C.0" "CAs scheduled; conditions NOT Installed + VERAE_SKIP_PRINTERS<>`"1`"; REMOVE~=`"ALL`" uninstall" Write-Step "C.1" "Default MSI install (or VERAE_SKIP_PRINTERS=0) elevated" Write-Step "C.2" "Program Files layout matches VM A (bin\, scripts\, docs)" @@ -200,7 +241,11 @@ Write-Step "C.6" "VERAE_SKIP_PRINTERS=1 skips CA; default installs printers" Write-Step "C.7" "msiexec /x removes printers, task, files, Start Menu; no orphan HKLM" Write-Step "C.8" "Repair / same-version upgrade smoke (AllowSameVersionUpgrades)" Write-Note "Do not mark dual-ship complete until VM C matches VM A on a clean image." -Write-Note "VM C sign-off: pass / fail / blocked (CAs commented) · initials" +if ($vmCBlocked) { + Write-Note "VM C sign-off: blocked (CAs not enabled) · initials" +} else { + Write-Note "VM C sign-off: pass / fail · initials (authoring enabled ≠ signed off)" +} # --- Side-by-side --- Write-Section "Side-by-side (tick when observed)" diff --git a/platform/windows/scripts/enable-printer-cas.ps1 b/platform/windows/scripts/enable-printer-cas.ps1 new file mode 100644 index 0000000..8c32c84 --- /dev/null +++ b/platform/windows/scripts/enable-printer-cas.ps1 @@ -0,0 +1,174 @@ +#Requires -Version 5.1 +<# +.SYNOPSIS + Enable or disable deferred printer CustomActions in Product-Full.wxs (VM C gate). + +.DESCRIPTION + Product-Full.wxs ships with printer/helper deferred CAs wrapped in + DEFERRED_PRINTER_CAS:OFF … DEFERRED_PRINTER_CAS:OFF comment markers so + candle/light stay files-only (VM B safe). + + -Enable (default): unwrap the body so WiX schedules CA_StopHelper, + CA_InstallPrinters (+ rollback), CA_UninstallPrinters. Rebuild MSI, then + run dual-ship VM C (DUAL-SHIP.md). Does not build, install, or sign. + -Disable: re-wrap the body (default tree state). + -Status: print enabled/disabled; exit 0 either way. + + dual-ship-smoke treats VM C as BLOCKED until CAs are enabled. Enabling here + does not complete dual-ship — clean-VM C parity with NSIS is still required. + +.EXITCODES + 0 Status printed, or file already in requested state, or toggle succeeded. + 1 Product-Full.wxs missing, markers missing/ambiguous, or write failed. + +.PARAMETER WxsPath + Path to Product-Full.wxs (default: sibling ../wix/Product-Full.wxs). + +.PARAMETER Enable + Uncomment the deferred CA body (default action when neither -Disable nor -Status). + +.PARAMETER Disable + Comment the deferred CA body again. + +.PARAMETER Status + Report only; do not modify the file. + +.EXAMPLE + powershell -NoProfile -ExecutionPolicy Bypass -File enable-printer-cas.ps1 -Status + +.EXAMPLE + powershell -NoProfile -ExecutionPolicy Bypass -File enable-printer-cas.ps1 + # then: build-full-msi.ps1 ; dual-ship-smoke.ps1 + +.EXAMPLE + powershell -NoProfile -ExecutionPolicy Bypass -File enable-printer-cas.ps1 -Disable +#> +param( + [string]$WxsPath = "", + [switch]$Enable, + [switch]$Disable, + [switch]$Status +) + +$ErrorActionPreference = "Stop" + +if (($Enable.IsPresent -and $Disable.IsPresent) -or + ($Enable.IsPresent -and $Status.IsPresent) -or + ($Disable.IsPresent -and $Status.IsPresent)) { + Write-Error "Use only one of -Enable, -Disable, or -Status." + exit 1 +} + +$mode = "enable" +if ($Disable) { $mode = "disable" } +elseif ($Status) { $mode = "status" } +elseif ($Enable) { $mode = "enable" } + +$ScriptDir = $PSScriptRoot +if (-not $WxsPath) { + $WxsPath = Join-Path $ScriptDir "..\wix\Product-Full.wxs" +} +$WxsPath = $PSCmdlet.SessionState.Path.GetUnresolvedProviderPathFromPSPath($WxsPath) + +if (-not (Test-Path -LiteralPath $WxsPath)) { + Write-Host ("FAIL: Product-Full.wxs not found: {0}" -f $WxsPath) -ForegroundColor Red + exit 1 +} + +# Marker pairs (non-overlapping strings): +# disabled: +# enabled: … +$OffOpen = "" +$OnOpen = "" +$OnClose = "" + +$text = [System.IO.File]::ReadAllText($WxsPath) + +function Get-CasState([string]$Content) { + $hasOff = $Content.Contains($OffOpen) -and $Content.Contains($OffClose) + $hasOn = $Content.Contains($OnOpen) -and $Content.Contains($OnClose) + if ($hasOff -and $hasOn) { return "ambiguous" } + if ($hasOn) { return "enabled" } + if ($hasOff) { return "disabled" } + if ($Content.Contains("DEFERRED_PRINTER_CAS:")) { return "ambiguous" } + return "missing" +} + +$state = Get-CasState $text +Write-Host ("Product-Full.wxs: {0}" -f $WxsPath) -ForegroundColor DarkGray +Write-Host ("Deferred printer CAs: {0}" -f $state) + +if ($state -eq "missing" -or $state -eq "ambiguous") { + Write-Host "FAIL: expected exactly one DEFERRED_PRINTER_CAS:OFF or :ON marker pair." -ForegroundColor Red + Write-Host " See platform/windows/wix/README.md § Enable printer CAs (VM C)." -ForegroundColor DarkGray + exit 1 +} + +if ($mode -eq "status") { + if ($state -eq "disabled") { + Write-Host "VM C: BLOCKED until enable-printer-cas.ps1 (then rebuild MSI + clean-VM parity)." -ForegroundColor Yellow + } else { + Write-Host "VM C: CAs live in authoring — still need rebuild + dual-ship VM C sign-off." -ForegroundColor Cyan + } + exit 0 +} + +if ($mode -eq "enable") { + if ($state -eq "enabled") { + Write-Host "Already enabled — no file change." -ForegroundColor Green + Write-Host "Next: build-full-msi.ps1 then dual-ship-smoke / VM C checklist." -ForegroundColor DarkGray + exit 0 + } + $idxOpen = $text.IndexOf($OffOpen) + $idxClose = $text.IndexOf($OffClose) + if ($idxOpen -lt 0 -or $idxClose -lt 0 -or $idxClose -le $idxOpen) { + Write-Host "FAIL: OFF markers not found in order." -ForegroundColor Red + exit 1 + } + $before = $text.Substring(0, $idxOpen) + $bodyStart = $idxOpen + $OffOpen.Length + $body = $text.Substring($bodyStart, $idxClose - $bodyStart) + $after = $text.Substring($idxClose + $OffClose.Length) + $text = $before + $OnOpen + $body + $OnClose + $after + $label = "enabled" +} else { + if ($state -eq "disabled") { + Write-Host "Already disabled — no file change." -ForegroundColor Green + Write-Host "VM C remains BLOCKED (dual-ship-smoke)." -ForegroundColor DarkGray + exit 0 + } + $idxOpen = $text.IndexOf($OnOpen) + $idxClose = $text.IndexOf($OnClose) + if ($idxOpen -lt 0 -or $idxClose -lt 0 -or $idxClose -le $idxOpen) { + Write-Host "FAIL: ON markers not found in order." -ForegroundColor Red + exit 1 + } + $before = $text.Substring(0, $idxOpen) + $bodyStart = $idxOpen + $OnOpen.Length + $body = $text.Substring($bodyStart, $idxClose - $bodyStart) + $after = $text.Substring($idxClose + $OnClose.Length) + $text = $before + $OffOpen + $body + $OffClose + $after + $label = "disabled" +} + +$utf8NoBom = New-Object System.Text.UTF8Encoding $false +[System.IO.File]::WriteAllText($WxsPath, $text, $utf8NoBom) + +$verify = Get-CasState $text +if ($verify -ne $label) { + Write-Host ("FAIL: after write, state is '{0}' (expected '{1}')." -f $verify, $label) -ForegroundColor Red + exit 1 +} + +Write-Host ("OK: deferred printer CAs {0} in Product-Full.wxs" -f $label) -ForegroundColor Green +if ($label -eq "enabled") { + Write-Host "Next:" -ForegroundColor DarkGray + Write-Host " 1) powershell -File platform\windows\scripts\build-full-msi.ps1" + Write-Host " 2) dual-ship-smoke.ps1 (VM C no longer authoring-blocked; clean-VM still required)" + Write-Host " 3) VM C parity vs VM A per DUAL-SHIP.md / VM-DUAL-SHIP-CHECKLIST.md" + Write-Host "Do not thin NSIS until dual-ship exit checklist A–D is checked." -ForegroundColor DarkGray +} else { + Write-Host "VM C: BLOCKED again until CAs re-enabled. Files-only MSI (VM B) remains the safe path." -ForegroundColor Yellow +} +exit 0 diff --git a/platform/windows/wix/DUAL-SHIP.md b/platform/windows/wix/DUAL-SHIP.md index 01f31d3..b0aebea 100644 --- a/platform/windows/wix/DUAL-SHIP.md +++ b/platform/windows/wix/DUAL-SHIP.md @@ -4,7 +4,7 @@ **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](../../../docs/COMMERCIAL-INSTALLER-BACKLOG.md), [CI-SIGN-NOTARY.md](CI-SIGN-NOTARY.md)). -**Related:** [Product-Full.wxs](Product-Full.wxs) · [SILENT_PROPS.md](SILENT_PROPS.md) · [VM-DUAL-SHIP-CHECKLIST.md](VM-DUAL-SHIP-CHECKLIST.md) (printable A/B/C) · [`dual-ship-smoke.ps1`](../scripts/dual-ship-smoke.ps1) (offline checklist runner + optional local MSI/NSIS hash) · [../installer-windows.nsi](../installer-windows.nsi) · [PACKAGING.md](../../../docs/PACKAGING.md) · site [DOWNLOADS-MANIFEST.md](../../../site/printit.verae.ai/DOWNLOADS-MANIFEST.md) (0.3.6 TBD rows) · [`fill-manifest-sha256.ps1`](../scripts/fill-manifest-sha256.ps1) (hash built MSI/NSIS → manifest row; no upload). +**Related:** [Product-Full.wxs](Product-Full.wxs) · [SILENT_PROPS.md](SILENT_PROPS.md) · [VM-DUAL-SHIP-CHECKLIST.md](VM-DUAL-SHIP-CHECKLIST.md) (printable A/B/C) · [`dual-ship-smoke.ps1`](../scripts/dual-ship-smoke.ps1) (offline checklist runner + optional local MSI/NSIS hash; **VM C blocked until CAs enabled**) · [`enable-printer-cas.ps1`](../scripts/enable-printer-cas.ps1) (uncomment deferred printer CAs in Product-Full for VM C) · [../installer-windows.nsi](../installer-windows.nsi) · [PACKAGING.md](../../../docs/PACKAGING.md) · site [DOWNLOADS-MANIFEST.md](../../../site/printit.verae.ai/DOWNLOADS-MANIFEST.md) (0.3.6 TBD rows) · [`fill-manifest-sha256.ps1`](../scripts/fill-manifest-sha256.ps1) (hash built MSI/NSIS → manifest row; no upload). --- @@ -92,9 +92,9 @@ Use two fresh Windows 10/11 **x64** VMs (or reset snapshots). Do **not** mix cha |----|---------|------| | **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 | +| **C — MSI printers** (when CAs enabled) | 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**. +Until printer CAs are **enabled** (`enable-printer-cas.ps1`), rebuilt into the MSI, and tested, treat **VM C as blocked**; dual-ship gate for “MSI can replace NSIS” stays **open**. `dual-ship-smoke.ps1` prints this block explicitly when Product-Full markers are still disabled. ### Shared pre-checks @@ -146,17 +146,26 @@ Interactive UI install is fine for smoke; `/qn` proves fleet syntax ([SILENT_PRO --- -## VM C — MSI printer CA (still left) +## VM C — MSI printer CA (still left / blocked until CAs enabled) -When uncommenting CAs in `Product-Full.wxs`: +Default tree keeps deferred CAs **commented** (`DEFERRED_PRINTER_CAS:OFF` markers). Enable when ready for VM C: -1. Schedule stubs (see commented `InstallExecuteSequence` in Product-Full) after `InstallFiles`. +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\enable-printer-cas.ps1 +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\build-full-msi.ps1 +``` + +(`enable-printer-cas.ps1 -Status` / `-Disable`; README § Enable printer CAs.) + +Then on the clean VM: + +1. Confirm schedule after enable (defs + `InstallExecuteSequence` after `InstallFiles`). 2. Conditions: `NOT Installed` and `VERAE_SKIP_PRINTERS<>"1"` for install; `REMOVE~="ALL"` for uninstall. 3. Deferred elevated: `install-printer.ps1 -InstallDir "[INSTALLFOLDER]"`; rollback/uninstall → `uninstall-printer.ps1`. 4. Re-run dual-ship **A vs C** parity: same printers, same helper task name, same IPP loopback `127.0.0.1:8631`. 5. Silent: `VERAE_SKIP_PRINTERS=1` must skip CA; default must install printers. -Do **not** mark dual-ship complete until VM C matches VM A on a clean image. +`dual-ship-smoke.ps1` notes **C blocked until CAs enabled**; enabling authoring is **not** a dual-ship pass. Do **not** mark dual-ship complete until VM C matches VM A on a clean image. --- @@ -281,6 +290,7 @@ Do **not** put PFX bytes or passwords in git. Do not upload the PFX as a workflo | Silent properties | [SILENT_PROPS.md](SILENT_PROPS.md) | | Printable VM A/B/C checklist | [VM-DUAL-SHIP-CHECKLIST.md](VM-DUAL-SHIP-CHECKLIST.md) | | Offline dual-ship smoke (print + optional hash) | [../scripts/dual-ship-smoke.ps1](../scripts/dual-ship-smoke.ps1) | +| Enable deferred printer CAs (VM C prereq) | [../scripts/enable-printer-cas.ps1](../scripts/enable-printer-cas.ps1) | | Sign/notary draft | [CI-SIGN-NOTARY.md](CI-SIGN-NOTARY.md) | | Menubar CI notary example | [../../macos/menubar/ci-notarize.yml.example](../../macos/menubar/ci-notarize.yml.example) | | Site 0.3.6 placeholders | [DOWNLOADS-MANIFEST.md](../../../site/printit.verae.ai/DOWNLOADS-MANIFEST.md) · [DOWNLOADS-MANIFEST.txt](../../../site/printit.verae.ai/DOWNLOADS-MANIFEST.txt) | diff --git a/platform/windows/wix/Product-Full.wxs b/platform/windows/wix/Product-Full.wxs index db868bd..62905d8 100644 --- a/platform/windows/wix/Product-Full.wxs +++ b/platform/windows/wix/Product-Full.wxs @@ -4,17 +4,18 @@ Status: candle/light-ready authoring. File Sources match StageFull layout produced by platform/windows/scripts/build-full-msi.ps1. - NOT commercial-ready: no Authenticode, printer CAs commented, dual-ship NSIS + NOT commercial-ready: no Authenticode, printer CAs default OFF + (DEFERRED_PRINTER_CAS:OFF; enable-printer-cas.ps1), dual-ship NSIS (see DUAL-SHIP.md). - Scope (wired File components; CAs still stubs): + Scope (wired File components; CAs default disabled): - perMachine / elevated → ProgramFiles64\Verae\PrintStamp - bin\verae-print.exe + bin\verae-printhelper.exe (required for light) - scripts\ (common, user-token, install/uninstall-printer, verae-diag) - LICENSE.txt + README-WINDOWS.txt - Start Menu shortcuts (non-advertised + HKLM keypath) - Public silent props (SILENT_PROPS.md) - - Printer CA + InstallExecuteSequence stubs commented (no binaries required) + - Printer CA + InstallExecuteSequence behind DEFERRED_PRINTER_CAS:OFF Not this package: - Tray presence → VeraeTrayShortcuts.wxs (per-user, non-elevated) @@ -123,7 +124,7 @@ @@ -134,17 +135,26 @@ + + DEFERRED_PRINTER_CAS:OFF--> diff --git a/platform/windows/wix/README.md b/platform/windows/wix/README.md index cd3aed1..2152d18 100644 --- a/platform/windows/wix/README.md +++ b/platform/windows/wix/README.md @@ -158,6 +158,38 @@ day-to-day full product. **Not** Authenticode-signed; printer CAs remain **commented** stubs (see `Product-Full.wxs`). Side-by-side NSIS+MSI validation: [DUAL-SHIP.md](DUAL-SHIP.md). +### Enable printer CAs (VM C) + +Deferred printer/helper CustomActions in `Product-Full.wxs` ship **disabled** +(wrapped in `DEFERRED_PRINTER_CAS:OFF` … `DEFERRED_PRINTER_CAS:OFF` comment +markers) so candle/light stay files-only — safe for dual-ship **VM B** +(`VERAE_SKIP_PRINTERS=1`). **VM C is blocked** until the body is enabled, +MSI rebuilt, and clean-VM parity with NSIS is signed off. + +```powershell +# Status (default tree = disabled → dual-ship-smoke marks VM C BLOCKED) +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\enable-printer-cas.ps1 -Status + +# Enable CAs for VM C authoring (does not build/install/sign) +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\enable-printer-cas.ps1 + +# Rebuild full MSI, then offline checklist (C no longer authoring-blocked) +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\build-full-msi.ps1 +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\dual-ship-smoke.ps1 + +# Re-disable (files-only default) +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\enable-printer-cas.ps1 -Disable +``` + +| Fact | Detail | +|------|--------| +| What enable does | Unwraps CA defs + `InstallExecuteSequence` in `Product-Full.wxs` only | +| What it does **not** | Build MSI, install printers, drive a VM, Authenticode, thin NSIS | +| dual-ship-smoke | Prints **VM C BLOCKED until CAs enabled**; enabling is a prereq, not a pass | +| After enable | Clean-VM C must match VM A (printers, helper task, skip prop) before dual-ship gate closes | + +Manual edit is fine: keep defs and schedule together; do not leave half-uncommented markers. + ### Files in this folder | File | Role | @@ -174,6 +206,7 @@ day-to-day full product. **Not** Authenticode-signed; printer CAs remain | `../scripts/build-full-msi.ps1` | Full StageFull + candle/light; WiX missing → exit 1 | | `../scripts/fill-manifest-sha256.ps1` | Hash built MSI/NSIS → DOWNLOADS-MANIFEST row (no upload) | | `../scripts/dual-ship-smoke.ps1` | Offline dual-ship checklist runner (print A/B/C; optional local hash) | +| `../scripts/enable-printer-cas.ps1` | Enable/disable deferred printer CAs in `Product-Full.wxs` (VM C prereq) | | `VM-DUAL-SHIP-CHECKLIST.md` | Printable clean-VM A/B/C tick sheet | ### Relation to other Windows paths @@ -187,6 +220,7 @@ day-to-day full product. **Not** Authenticode-signed; printer CAs remain | `../scripts/build-full-msi.ps1` | Stages StageFull + builds full MSI when WiX is installed | | `../scripts/fill-manifest-sha256.ps1` | Local SHA-256 rows for site DOWNLOADS-MANIFEST (no upload) | | `../scripts/dual-ship-smoke.ps1` | Offline print of dual-ship A/B/C steps + optional MSI/NSIS verify/hash | +| `../scripts/enable-printer-cas.ps1` | Toggle deferred printer CAs in Product-Full (default off; VM C needs on) | | `../installer-windows.nsi` | Elevated **full product** setup.exe (primary until MSI validated) | | **`wix/` (this folder)** | Tray skeleton + full Product-Full authoring | diff --git a/platform/windows/wix/VM-DUAL-SHIP-CHECKLIST.md b/platform/windows/wix/VM-DUAL-SHIP-CHECKLIST.md index 3aaf4f4..125c735 100644 --- a/platform/windows/wix/VM-DUAL-SHIP-CHECKLIST.md +++ b/platform/windows/wix/VM-DUAL-SHIP-CHECKLIST.md @@ -79,9 +79,9 @@ UI install is fine for smoke; `/qn` proves fleet syntax. --- -## VM C — MSI printer CA (still left / blocked until CAs live) +## VM C — MSI printer CA (still left / blocked until CAs enabled) -**Prerequisites:** uncomment + schedule deferred CAs in `Product-Full.wxs` (`InstallExecuteSequence` after `InstallFiles`); rebuild MSI. +**Prerequisites:** enable deferred CAs in `Product-Full.wxs` via [`../scripts/enable-printer-cas.ps1`](../scripts/enable-printer-cas.ps1) (or manually unwrap `DEFERRED_PRINTER_CAS:OFF` markers); rebuild MSI. `dual-ship-smoke.ps1` prints **VM C BLOCKED** while markers are disabled — enabling is not a dual-ship pass. | # | Step | Result / notes | ☐ | |---|------|----------------|---|