feat: commercial installer scaffold — WiX tray MSI skeleton + notarize checklist

Non-elevated tray shortcuts wxs; NOTARIZE-CHECKLIST; backlog scaffold section.
This commit is contained in:
George Lambert 2026-10-13 22:25:50 -04:00
commit b72324edc4
5 changed files with 497 additions and 5 deletions

View file

@ -8,6 +8,20 @@ Day-to-day packaging (tray, menu bar, version stamps, CERT-01, IPP GET vs POST)
---
## 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) | Non-elevated **per-user** WiX v3 product + shortcut fragment: stages `verae-tray.ps1`, Start Menu `Programs\Verae\Verae Tray.lnk`, Startup `Verae Tray.lnk`. Build when **candle/light** (or adapted WiX v4) are present. | Full elevated commercial MSI (printers, Program Files, Authenticode, NSIS parity, CI-signed MSI in `dist/`). No MSI binary is produced in-repo without the WiX toolset. |
| **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 CI keychain import. |
**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`.
---
## Goals (definition of done)
| Platform | Ship artifact | Done when |
@ -33,6 +47,7 @@ Related but out of scope for “done” above (still backlog-adjacent): Linux `.
| 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/) (`VeraeTrayShortcuts.wxs` + fragment + README) | **Scaffold shipped** — Start Menu + Startup → `verae-tray.ps1` only; needs candle/light to emit MSI |
| Shared version helper | [`platform/windows/scripts/common.ps1`](../platform/windows/scripts/common.ps1) `Get-VeraePackageVersion` | Aligns tray scripts 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 |
@ -45,7 +60,7 @@ NSIS product already covers much of the *install experience* (files under Progra
| Gap | Why it matters | Suggested work |
|-----|----------------|----------------|
| **No WiX project** (no `.wxs` / `.wixproj`, no `candle`/`light` or WiX v4 `wix build`) | Enterprise wants MSI, not only `setup.exe` | Author WiX that installs the same payload NSIS stages: `verae-print.exe`, helper, scripts, LICENSE, printers custom action |
| **No full-product WiX project** (tray skeleton only under `platform/windows/wix/`) | Enterprise wants MSI with same payload as NSIS, not only `setup.exe` or tray shortcuts | Extend or replace tray skeleton with WiX that installs NSIS surface: `verae-print.exe`, helper, scripts, LICENSE, printers custom action |
| **No MSI output artifact** in `dist/` or CI | Nothing to hand Intune/SCCM | Produce `VeraePrintStamp-windows-<arch>-<version>.msi` (+ SHA256) |
| **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 |
| **Silent / unattended install contract** | Fleet deploy | Document and implement `msiexec /i … /qn` properties (e.g. skip key UI, `VERAE_SKIP_KEY_SETUP`, install API URL, channel) |
@ -82,6 +97,7 @@ NSIS product already covers much of the *install experience* (files under Progra
| 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 |
| 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`
@ -130,13 +146,15 @@ NSIS product already covers much of the *install experience* (files under Progra
|-------------|--------|------------------|
| 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) | **No** | **No** |
| Windows **MSI** (WiX) tray presence skeleton | **Yes** (`.wxs` + README under `platform/windows/wix/`) | **No** — scaffold only; needs toolset build + is not full product MSI |
| Windows **MSI** full product (NSIS parity) | **No** | **No** |
| Windows Authenticode pipeline | **No** (in-repo) | **No** |
| 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 automated notarization | Docs only | **No** |
| Menubar notarize checklist | **Yes** (`NOTARIZE-CHECKLIST.md`) | Docs only — not automated |
| Menubar automated notarization | Docs + checklist only | **No** |
---
@ -144,8 +162,10 @@ NSIS product already covers much of the *install experience* (files under Progra
- **[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/) — per-user tray shortcut MSI **skeleton** (candle/light)
- [`platform/macos/pkg/`](../platform/macos/pkg/) — commercial `.pkg` build
- [`platform/macos/menubar/`](../platform/macos/menubar/) — menu bar + unsigned `.app` + notarize docs
- [`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
- [`docs/installer-registration-api.md`](installer-registration-api.md) — installer ↔ portal registration API
- [`README.md`](../README.md) — top-level packaging pointers
@ -153,4 +173,4 @@ NSIS product already covers much of the *install experience* (files under Progra
## Maintenance
When closing a row above, update the **Quick status matrix** and add a one-line note under the relevant “Exists” table (path + date). Do not move day-to-day tray/menubar how-to out of [PACKAGING.md](PACKAGING.md) into this backlog.
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.

View file

@ -0,0 +1,166 @@
# Menu bar `.app` notarization checklist
Step list for **Developer ID** codesign + **notarytool** + **stapler** of the
optional Verae menu bar app (`ai.verae.timestamping.menubar`).
This is a **checklist only**. It does **not** embed API keys, `.p12` material,
app-specific passwords, or `signing.env` values. Keep credentials in the
keychain, CI secrets, or an out-of-repo env file (e.g. the pkg path’s
`$HOME/fie/installers/macos/signing.env`).
Related runbooks: [`README.txt`](README.txt), [`docs/PACKAGING.md`](../../../docs/PACKAGING.md)
§ Codesign + notarization, [`platform/macos/pkg/build-pkg.sh`](../pkg/build-pkg.sh)
(product `.pkg`, separate from this menubar stub).
---
## Prerequisites (once per machine / CI)
- [ ] Apple Developer Program membership; team id known (`TEAM_ID=…` placeholder)
- [ ] **Developer ID Application** certificate installed in the signing keychain
- [ ] Notary credentials stored **outside git**, one of:
- [ ] Keychain profile via `xcrun notarytool store-credentials`
(profile name placeholder: `verae-notary`)
- [ ] App Store Connect API key: `AuthKey_XXXXXXXXXX.p8` path + Key ID + Issuer ID
(paths/ids as env placeholders only — never commit the `.p8`)
- [ ] Xcode CLT with `codesign`, `notarytool`, `stapler`, `spctl`, `ditto`
- [ ] Entitlements file available (builder copies pkg entitlements into the app):
`platform/macos/pkg/entitlements.plist` or
`$APP/Contents/Resources/entitlements.plist` after build
**Do not** paste secrets into this checklist or the repo.
---
## Build unsigned app
- [ ] From repo root or `platform/macos/menubar/`:
```sh
./build-menubar-app.sh ~/Applications/Verae\ Menubar.app
# optional version pin (default = internal/job.HelperVersion):
# VERSION=x.y.z ./build-menubar-app.sh ~/Applications/Verae\ Menubar.app
```
- [ ] Confirm bundle id `ai.verae.timestamping.menubar`, `LSUIElement=true`
- [ ] Confirm `Contents/Resources/VERSION` and `packaging-metadata.txt` match
`HelperVersion` (or your `VERSION=` override)
---
## Codesign (hardened runtime)
Placeholders: `YOUR ORG`, `TEAMID`, `APP`.
```sh
APP="${APP:-$HOME/Applications/Verae Menubar.app}"
ENT="$APP/Contents/Resources/entitlements.plist"
# fallback: ENT="../../pkg/entitlements.plist" from menubar dir
IDENTITY="Developer ID Application: YOUR ORG (TEAMID)"
codesign --force --deep --options runtime --timestamp \
--entitlements "$ENT" \
--sign "$IDENTITY" \
"$APP"
codesign --verify --deep --strict --verbose=2 "$APP"
codesign -dvv "$APP" # inspect hardened runtime + team
```
- [ ] `codesign --verify` succeeds
- [ ] Hardened runtime present (`flags=0x10000(runtime)` or equivalent)
- [ ] No unexpected nested Mach-O left unsigned (menubar is a thin Swift binary)
---
## Zip for notarytool
```sh
ZIP="${ZIP:-/tmp/VeraeMenubar.zip}"
rm -f "$ZIP"
ditto -c -k --keepParent "$APP" "$ZIP"
```
- [ ] Zip created with `--keepParent` (bundle layout preserved)
---
## Submit notarization (`notarytool`)
### Option A — keychain profile (preferred on operator laptops)
```sh
# One-time (interactive; stores in keychain — not in git):
# xcrun notarytool store-credentials "verae-notary" \
# --apple-id "YOUR_APPLE_ID@example.com" \
# --team-id "TEAMID" \
# --password "@keychain:AC_PASSWORD" # or app-specific password prompt
xcrun notarytool submit "$ZIP" \
--keychain-profile "verae-notary" \
--wait
```
### Option B — App Store Connect API key (CI-friendly)
```sh
# Env placeholders only — inject from CI secrets / signing.env:
# NOTARY_KEY_PATH=/path/to/AuthKey_XXXXXXXXXX.p8
# NOTARY_KEY_ID=XXXXXXXXXX
# NOTARY_ISSUER_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
xcrun notarytool submit "$ZIP" \
--key "$NOTARY_KEY_PATH" \
--key-id "$NOTARY_KEY_ID" \
--issuer "$NOTARY_ISSUER_ID" \
--wait
```
- [ ] Submission status **Accepted**
- [ ] On **Invalid**: `xcrun notarytool log <submission-id> --keychain-profile "verae-notary"`
(or same key flags as submit); fix entitlements / signing; do not commit logs with tokens
---
## Staple + Gatekeeper verify
```sh
xcrun stapler staple "$APP"
xcrun stapler validate "$APP"
spctl --assess --type execute -vv "$APP"
```
- [ ] `stapler validate` OK
- [ ] `spctl --assess` accepted (source = Notarized Developer ID)
- [ ] Optional: copy app to a **clean Mac / fresh user**, confirm no right-click Open workaround
---
## Distribute (optional)
- [ ] Publish stapled `.app` as zip or DMG + SHA256 (naming example:
`VeraeMenubar-<HelperVersion>.app.zip`)
- [ ] If DMG: notarize/staple the **DMG** as well when it is the download vessel
- [ ] Do **not** ship unstapled builds as the primary customer download
- [ ] Product `.pkg` path remains separate: `../pkg/build-pkg.sh` (already has
notarytool + stapler when `SIGNING_ENV` is set)
---
## Automation gap (still backlog)
- [ ] Wire `build-menubar-app.sh` (or shared `sign-and-notarize.sh`) to run the
above when `SIGNING_ENV` / CI secrets exist; keep **unsigned default** for dev
- [ ] CI macOS runner: import Developer ID + notary key → staple → upload checksums
- [ ] Smoke: `spctl` + `stapler validate` on signed hosts only
Until those land, this checklist is the operator runbook.
---
## Secrets hygiene (standing rules)
- Never commit `signing.env`, `.p8`, `.p12`, notary passwords, or keychain exports
- Never put real Apple IDs, Team IDs used as production secrets, or API key IDs
into sample commands in PRs if policy forbids — placeholders only
- Rotate credentials out-of-band if leaked; revoke via App Store Connect

View file

@ -0,0 +1,132 @@
# Windows WiX tray presence (skeleton)
[![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
Non-elevated per-user WiX MSI skeleton for Start Menu + Startup → verae-tray.ps1.
This is **not** the full commercial Print Stamp MSI (printers, Program Files,
Authenticode, elevated custom actions). Day-to-day tray presence without WiX
remains [`../scripts/build-tray-startmenu.ps1`](../scripts/build-tray-startmenu.ps1).
Full product install remains NSIS (`../installer-windows.nsi`). Commercial gaps:
[`docs/COMMERCIAL-INSTALLER-BACKLOG.md`](../../../docs/COMMERCIAL-INSTALLER-BACKLOG.md).
## Install
Requires **WiX Toolset** on a Windows host (or CI Windows runner). Without
`candle`/`light` (or WiX v4 `wix build`), no MSI is produced — use the
PowerShell Start Menu stub instead.
**WiX v3** (this skeleton’s XML):
```bat
REM Add candle.exe + light.exe to PATH, e.g.:
REM set PATH=%PATH%;%ProgramFiles(x86)%\WiX Toolset v3.14\bin
```
**WiX v4+** (`dotnet tool install --global wix`): adapt namespaces / `Package`
element; authoring here is WiX v3.
Stage tray scripts from this repo before building:
```bat
set WIXDIR=platform\windows\wix
set STAGE=%WIXDIR%\Stage
mkdir %STAGE% 2>nul
copy /Y platform\windows\scripts\verae-tray.ps1 %STAGE%\
copy /Y platform\windows\scripts\common.ps1 %STAGE%\
```
## Usage
### What the package does
| Item | Behavior |
|------|----------|
| Install scope | **perUser**, `InstallPrivileges=limited` (no UAC) |
| Files | `%LocalAppData%\Verae\Tray\verae-tray.ps1` (+ `common.ps1`) |
| Start Menu | `Programs\Verae\Verae Tray.lnk` → PowerShell STA + tray script |
| Startup | `Startup\Verae Tray.lnk` (same idea as `install-tray-startup.ps1`) |
| IPP | Unchanged — tray only uses **GET `/status`** / **GET `/queue`** |
### What it does not do
Elevated Program Files install, printers, scheduled helper, Authenticode,
NSIS key wizard parity, machine-wide Start Menu under ProgramData.
### Build (WiX v3 candle / light)
From repo root on Windows:
```bat
set WIXDIR=platform\windows\wix
set STAGE=%WIXDIR%\Stage
set OUT=%WIXDIR%\out
set VER=0.3.6
mkdir %STAGE% 2>nul
mkdir %OUT% 2>nul
copy /Y platform\windows\scripts\verae-tray.ps1 %STAGE%\
copy /Y platform\windows\scripts\common.ps1 %STAGE%\
candle.exe -nologo -out %OUT%\ ^
-dProductVersion=%VER% ^
-dStageDir=%CD%\%STAGE% ^
%WIXDIR%\VeraeTrayShortcuts.wxs ^
%WIXDIR%\VeraeTrayShortcutsFragment.wxs
light.exe -nologo -out %OUT%\VeraeTray-%VER%-peruser.msi ^
%OUT%\VeraeTrayShortcuts.wixobj ^
%OUT%\VeraeTrayShortcutsFragment.wixobj
```
Notes:
- Set `VER` from `internal/job.HelperVersion` (see `docs/PACKAGING.md`), or
pass `-dProductVersion=` explicitly. The `.wxs` defaults to `0.3.6` when
unset (HelperVersion at scaffold time).
- `Product Id="*"` generates a new ProductCode per build; `UpgradeCode` is
fixed for major-upgrade of this **tray presence** package only.
- Skeleton is **UI-less** (silent-friendly). For WixUI_Minimal, uncomment
`UIRef` / `WixUILicenseRtf` in `VeraeTrayShortcuts.wxs`, add `License.rtf`,
and pass `-ext WixUIExtension` to `light`.
Silent install (per-user, no elevation):
```bat
msiexec /i VeraeTray-0.3.6-peruser.msi /qn VERAE_IPP_ADDR=127.0.0.1:8631
```
Uninstall via ARP (**Verae Tray (presence)**) or `msiexec /x {ProductCode} /qn`.
### Files in this folder
| File | Role |
|------|------|
| `VeraeTrayShortcuts.wxs` | Per-user Product + file components |
| `VeraeTrayShortcutsFragment.wxs` | Start Menu + Startup shortcut fragment |
| `README.md` | This file |
### Relation to other Windows paths
| Path | Role |
|------|------|
| `../scripts/verae-tray.ps1` | Runtime tray (source staged into MSI) |
| `../scripts/install-tray-startup.ps1` | WiX-free Startup shortcut |
| `../scripts/build-tray-startmenu.ps1` | WiX-free Start Menu + Startup |
| `../installer-windows.nsi` | Elevated **full product** setup.exe |
| **`wix/` (this folder)** | Per-user tray shortcut **MSI skeleton** |
A shipping-grade elevated MSI still needs a separate WiX product that mirrors
NSIS: `verae-print.exe`, helper, printers, ARP, Authenticode, silent
properties, and CI.
## Contributing
Questions and packaging bugs: open an issue or PR against the PrintToVeraeTimeStamp
tree. PRs accepted for WiX authoring that keep **per-user / non-elevated** tray
scope separate from the full elevated product MSI. Do not commit certs,
passwords, or signed binaries.
## License
UNLICENSED © Verae

View file

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Verae tray presence MSI skeleton (non-elevated / per-user).
Scope: Start Menu + Startup shortcuts that launch verae-tray.ps1
(NotifyIcon, GET /status only). Does NOT install printers, Program Files
payload, scheduled helper, or elevated product bits — those remain NSIS
(installer-windows.nsi) or a future full commercial WiX product.
InstallPrivileges="limited" + InstallScope="perUser" — no UAC elevation.
Requires WiX Toolset (candle + light, or WiX v4 `wix build`) to produce MSI.
See README.md in this folder.
Version default tracks internal/job.HelperVersion; override at candle time:
-dProductVersion=x.y.z
-->
<?ifndef ProductVersion ?>
<?define ProductVersion = "0.3.6" ?>
<?endif?>
<?ifndef StageDir ?>
<?define StageDir = "Stage" ?>
<?endif?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Product
Id="*"
Name="Verae Tray (presence)"
Language="1033"
Version="$(var.ProductVersion)"
Manufacturer="Verae"
UpgradeCode="A7C3E91B-4D2F-4B8A-9E61-0F3C8D2A5B17">
<Package
InstallerVersion="500"
Compressed="yes"
InstallScope="perUser"
InstallPrivileges="limited"
Manufacturer="Verae"
Description="User-level Start Menu + Startup shortcuts for verae-tray.ps1. No elevation. Hold ids are never evidence."
Comments="Skeleton MSI — tray presence only. Full product MSI is a separate WiX project." />
<MajorUpgrade
DowngradeErrorMessage="A newer version of Verae Tray is already installed."
AllowSameVersionUpgrades="yes" />
<MediaTemplate EmbedCab="yes" />
<!-- ARP: presence package, not full Print Stamp product -->
<Property Id="ARPURLINFOABOUT" Value="https://printit.verae.ai/" />
<Property Id="ARPHELPLINK" Value="https://customer.verae.ai/portal/" />
<Property Id="ARPCOMMENTS" Value="User-level tray only (GET /status). Not the elevated Print Stamp installer." />
<!-- Hide modify; uninstall is enough for a shortcut package -->
<Property Id="ARPNOREPAIR" Value="1" />
<Property Id="ARPNOMODIFY" Value="1" />
<!-- Optional override for helper loopback (matches install-tray-startup.ps1 -Addr) -->
<Property Id="VERAE_IPP_ADDR" Value="127.0.0.1:8631" />
<Feature Id="TrayPresence" Title="Verae Tray shortcuts" Level="1"
Description="Start Menu folder + login Startup shortcut to verae-tray.ps1">
<ComponentGroupRef Id="TrayFiles" />
<ComponentGroupRef Id="TrayShortcuts" />
</Feature>
<!--
UI optional: WixUI_Minimal needs License.rtf beside the .wxs files.
For silent-only skeleton builds, comment out the next two lines and omit -ext WixUIExtension.
Silent: msiexec /i VeraeTray.msi /qn
-->
<!-- <UIRef Id="WixUI_Minimal" /> -->
<!-- <WixVariable Id="WixUILicenseRtf" Value="License.rtf" /> -->
</Product>
<Fragment>
<!--
Per-user layout under %LocalAppData%\Verae\Tray\
Harvest/copy verae-tray.ps1 (+ optional common.ps1) into StageDir before light.
-->
<Directory Id="TARGETDIR" Name="SourceDir">
<Directory Id="LocalAppDataFolder">
<Directory Id="VeraeAppData" Name="Verae">
<Directory Id="INSTALLFOLDER" Name="Tray" />
</Directory>
</Directory>
<!-- User Start Menu\Programs -->
<Directory Id="ProgramMenuFolder">
<Directory Id="VeraeStartMenuDir" Name="Verae" />
</Directory>
<!-- User Startup (login) -->
<Directory Id="StartupFolder" />
</Directory>
</Fragment>
<Fragment>
<ComponentGroup Id="TrayFiles" Directory="INSTALLFOLDER">
<!--
Stage files next to this .wxs (or set -dStageDir=... and adjust Source).
Required at build time: Stage\verae-tray.ps1
Optional: Stage\common.ps1 (Get-VeraePackageVersion helper)
-->
<Component Id="CmpVeraeTrayPs1" Guid="B1E8D4A0-2C5F-4A91-8D3E-7F6A0B9C1D2E">
<File Id="FileVeraeTrayPs1" Name="verae-tray.ps1"
Source="$(var.StageDir)\verae-tray.ps1" KeyPath="yes" />
</Component>
<Component Id="CmpCommonPs1" Guid="C2F9E5B1-3D60-4B02-9E4F-8A7B1C0D2E3F">
<File Id="FileCommonPs1" Name="common.ps1"
Source="$(var.StageDir)\common.ps1" KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
<!-- Shortcut components live in VeraeTrayShortcutsFragment.wxs (same Product link via ComponentGroupRef). -->
</Wix>

View file

@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Non-elevated shortcut fragment for Verae tray presence MSI.
Creates:
Start Menu\Programs\Verae\Verae Tray.lnk
Startup\Verae Tray.lnk
Both target powershell.exe -STA -File verae-tray.ps1 (GET /status only).
Include alongside VeraeTrayShortcuts.wxs when running candle/light.
Full commercial MSI (printers, Program Files, Authenticode, elevated
custom actions) is NOT this fragment — see docs/COMMERCIAL-INSTALLER-BACKLOG.md.
-->
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<Fragment>
<ComponentGroup Id="TrayShortcuts">
<!-- Start Menu: Programs\Verae\Verae Tray.lnk -->
<Component Id="CmpStartMenuTray" Directory="VeraeStartMenuDir"
Guid="D3A0F6C2-4E71-4C13-AF50-9B8C2D1E3F40">
<Shortcut
Id="ScStartMenuTray"
Name="Verae Tray"
Description="Verae Timestamping tray — polls GET /status; Open queue → /queue. Hold id ≠ evidence."
Target="[WindowsFolder]System32\WindowsPowerShell\v1.0\powershell.exe"
Arguments="-NoProfile -ExecutionPolicy Bypass -STA -WindowStyle Hidden -File &quot;[INSTALLFOLDER]verae-tray.ps1&quot; -Addr [VERAE_IPP_ADDR]"
WorkingDirectory="INSTALLFOLDER"
Show="minimized" />
<!-- KeyPath registry under HKCU so per-user uninstall is clean -->
<RegistryValue
Root="HKCU"
Key="Software\Verae\PrintStamp\Tray"
Name="StartMenuShortcut"
Type="integer"
Value="1"
KeyPath="yes" />
<RemoveFolder Id="RemoveVeraeStartMenuDir" Directory="VeraeStartMenuDir" On="uninstall" />
</Component>
<!-- Startup: login-time tray (same as install-tray-startup.ps1) -->
<Component Id="CmpStartupTray" Directory="StartupFolder"
Guid="E4B1A7D3-5F82-4D24-B061-0C9D3E2F4051">
<Shortcut
Id="ScStartupTray"
Name="Verae Tray"
Description="Verae Timestamping tray at login — polls GET /status. Hold id ≠ evidence."
Target="[WindowsFolder]System32\WindowsPowerShell\v1.0\powershell.exe"
Arguments="-NoProfile -ExecutionPolicy Bypass -STA -WindowStyle Hidden -File &quot;[INSTALLFOLDER]verae-tray.ps1&quot; -Addr [VERAE_IPP_ADDR]"
WorkingDirectory="INSTALLFOLDER"
Show="minimized" />
<RegistryValue
Root="HKCU"
Key="Software\Verae\PrintStamp\Tray"
Name="StartupShortcut"
Type="integer"
Value="1"
KeyPath="yes" />
</Component>
</ComponentGroup>
</Fragment>
</Wix>