From c2c87274be45e7a1e6264e60dff170315d163b2a Mon Sep 17 00:00:00 2001 From: George Lambert Date: Tue, 13 Oct 2026 21:46:33 -0400 Subject: [PATCH] docs: PACKAGING.md for tray, menubar, CERT, and statuslang Document HelperVersion packaging paths and evidence rules. --- README.md | 7 ++ docs/PACKAGING.md | 255 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 262 insertions(+) create mode 100644 docs/PACKAGING.md diff --git a/README.md b/README.md index 93ac918..b1b6f23 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,7 @@ PrintIt desktop/CLI path: stamp documents via Verae edge billing (xVerae keys). - [Background](#background) - [Install](#install) - [Usage](#usage) +- [Packaging](#packaging) - [Contributing](#contributing) - [License](#license) @@ -48,6 +49,12 @@ verae-print pending --html # offline queue page # Direct chain only with VERAE_ALLOW_DIRECT_VERAE=1 ``` +## Packaging + +Tray, menu bar, CERT-01 digests, version stamps (`HelperVersion` **0.3.6**), and IPP GET vs POST split: + +- [docs/PACKAGING.md](docs/PACKAGING.md) — Windows tray (no elevated MSI), macOS LaunchAgent / unsigned `.app` / notarization (docs only), `pending` / `tray-status` / `menubar`, statuslang notify titles, hold ≠ evidence. + ## Contributing Questions: open an issue on the project Forgejo/GitHub remote, or contact Verae engineering. diff --git a/docs/PACKAGING.md b/docs/PACKAGING.md new file mode 100644 index 0000000..fdf517c --- /dev/null +++ b/docs/PACKAGING.md @@ -0,0 +1,255 @@ +# PrintIt packaging (tray, menubar, CERT) + +Desktop packaging for PrintToVeraeTimeStamp: version stamps, Windows tray / +Start Menu presence (no elevated MSI), macOS menu bar / LaunchAgent / +optional unsigned `.app`, CERT-01 digests, statuslang notify titles, and the +split between pure GET status routes and the IPP POST print path. + +## Version source of truth + +| Item | Value / location | +|------|------------------| +| Constant | `internal/job.HelperVersion` = **`0.3.6`** | +| File | [`internal/job/job.go`](../internal/job/job.go) | +| Sidecar field | `"helper_version"` on every `.verae.json` | + +All packaging metadata must resolve from that constant (or fall back to the +same string when `job.go` is not on disk): + +- Windows: `platform/windows/scripts/common.ps1` → `Get-VeraePackageVersion` + (fallback `"0.3.6"`). Used by `verae-tray.ps1`, `install-tray-startup.ps1`, + `build-tray-startmenu.ps1`. +- macOS: `platform/macos/menubar/build-menubar-app.sh` reads `job.go` when + `VERSION` is unset; stamps `CFBundleShortVersionString` / + `CFBundleVersion`, `Contents/Resources/VERSION`, and + `packaging-metadata.txt`. +- Binary build: `scripts/build-win-linux.sh` greps `HelperVersion` from + `job.go`. +- Smoke: `platform/smoke-packaging-metadata.sh` fails if tray/menubar scripts + drift from `HelperVersion`. + +Override for a one-off stamp: `VERSION=x.y.z` (env) on the build/install +scripts. Do not invent a second version constant. + +## Windows tray (no elevated MSI) + +User-level presence only. **No elevated MSI**, no admin rights, no WiX +requirement for the tray stub. + +| Script | Role | +|--------|------| +| [`platform/windows/scripts/verae-tray.ps1`](../platform/windows/scripts/verae-tray.ps1) | STA NotifyIcon; polls **GET `/status`**; menu opens **GET `/queue`** | +| [`platform/windows/scripts/install-tray-startup.ps1`](../platform/windows/scripts/install-tray-startup.ps1) | Startup-folder shortcut (`Verae Tray.lnk`) that runs `verae-tray.ps1` | +| [`platform/windows/scripts/build-tray-startmenu.ps1`](../platform/windows/scripts/build-tray-startmenu.ps1) | WiX-free Start Menu folder stub; also installs Startup unless `-NoStartup` | + +CLI entry points (same behavior): + +```bat +verae-print menubar +verae-print menubar --install +verae-print menubar --uninstall +``` + +Or invoke the scripts directly: + +```powershell +powershell -NoProfile -ExecutionPolicy Bypass -STA -File platform\windows\scripts\verae-tray.ps1 +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\install-tray-startup.ps1 +powershell -NoProfile -ExecutionPolicy Bypass -File platform\windows\scripts\build-tray-startmenu.ps1 +``` + +Notes: + +- Package version in shortcut description / tooltip = `HelperVersion`. +- Full product installer (NSIS) is separate: see Windows README / + `installer-windows.nsi` when present. Tray packaging does **not** depend on it. +- Hold count in the tray is a **local queue handle**, never evidence + (`statuslang.EvidenceNote`). + +More detail: [`platform/windows/README.txt`](../platform/windows/README.txt). + +## macOS menu bar + +NSStatusItem that polls helper **GET `/status`** and opens **GET `/queue`**. +Does not touch IPP POST. + +| Asset | Role | +|-------|------| +| `platform/macos/menubar/verae-menubar.swift` | NSStatusItem source | +| `platform/macos/menubar/run-menubar.sh` | Compile-or-interpret entry | +| `platform/macos/menubar/com.verae.timestamping.menubar.plist` | LaunchAgent template | +| `platform/macos/menubar/build-menubar-app.sh` | Optional **unsigned** `.app` builder | +| `platform/macos/menubar/README.txt` | Runbook + **notarization steps (docs only)** | + +### Run / install + +```sh +verae-print menubar +verae-print menubar --foreground +verae-print menubar --install # LaunchAgent at login +verae-print menubar --uninstall +./platform/macos/menubar/run-menubar.sh +``` + +`--install` copies durable assets to +`~/Library/Application Support/Verae/menubar/` and writes +`~/Library/LaunchAgents/com.verae.timestamping.menubar.plist` +(`launchctl bootstrap`, fallback `load -w`). Prefer LaunchAgent over Login +Items for headless reliability. + +### Unsigned `.app` + +```sh +./platform/macos/menubar/build-menubar-app.sh +./platform/macos/menubar/build-menubar-app.sh ~/Applications/Verae\ Menubar.app +VERSION=0.3.6 ./platform/macos/menubar/build-menubar-app.sh +``` + +- `LSUIElement=true` (menu bar only, no Dock). +- Bundle id: `ai.verae.timestamping.menubar`. +- **Not codesigned or notarized by default** — local/dev use. +- Builder copies `platform/macos/pkg/entitlements.plist` into + `Contents/Resources/` for optional signing; it does not apply `codesign` + and never embeds secrets. + +### Codesign + notarization (document only) + +Requires Apple Developer Program + Developer ID Application cert in the +keychain. This repo does **not** ship secrets or `signing.env` values. +When certs are available (steps also in +[`platform/macos/menubar/README.txt`](../platform/macos/menubar/README.txt)): + +1. Build unsigned app: + `./build-menubar-app.sh ~/Applications/Verae\ Menubar.app` +2. Codesign hardened runtime + entitlements: + ```sh + APP="$HOME/Applications/Verae Menubar.app" + ENT="$APP/Contents/Resources/entitlements.plist" + codesign --force --deep --options runtime --timestamp \ + --entitlements "$ENT" \ + --sign "Developer ID Application: YOUR ORG (TEAMID)" \ + "$APP" + codesign --verify --deep --strict --verbose=2 "$APP" + ``` +3. Zip: `ditto -c -k --keepParent "$APP" /tmp/VeraeMenubar.zip` +4. Notarize: `xcrun notarytool submit /tmp/VeraeMenubar.zip --keychain-profile "verae-notary" --wait` +5. Staple: `xcrun stapler staple "$APP"` then `xcrun stapler validate "$APP"` +6. Optional signed `.pkg`: `platform/macos/pkg/build-pkg.sh` (Developer ID + Installer + `productbuild`) — separate from the menu-bar stub. + +Gatekeeper: unsigned app needs right-click → Open once, or +`xattr -dr com.apple.quarantine "Verae Menubar.app"`. Do not paste API keys, +app-specific passwords, or `.p12` material into the repo. + +## CLI surface: pending / tray-status / menubar + +| Command | Purpose | +|---------|---------| +| `verae-print serve` | IPP helper + loopback **GET `/queue`**, **GET `/status`**, **GET `/`** (health) | +| `verae-print tray-status` | Offline/online held · key · helper snapshot (`statuslang` headlines) | +| `verae-print tray-status --open` | Open live `http://127.0.0.1:8631/queue` (or temp HTML if helper down) | +| `verae-print menubar` | PT-W3 / PT-06: Windows tray or macOS menu bar | +| `verae-print menubar --install` / `--uninstall` | Login presence (Startup / LaunchAgent) | +| `verae-print pending --html` | Offline queue page (same HTML family as live `/queue`) | + +Default loopback: `127.0.0.1:8631` (`VERAE_IPP_ADDR` overrides). + +## CERT-01: multihash / blake3 when present + +Branded certificate path: `internal/pdfcert` (CERT-01 plum/gold, final-only +wording). Job path always prefers local CERT-01 over upstream attach PDF. + +| Digest | When shown | Multihash form | +|--------|------------|----------------| +| SHA-256 | Always when stamp hash is known | `f1220` + 64 hex (`pdfcert.ContentMultihash`) | +| BLAKE3 | **Only** when `Options.Blake3` / upstream provides it | `f1e20` + 64 hex; omit fields when empty | + +Rules: + +- **Never invent** digests. Empty blake3 → omit `blake3` / + `blake3_multihash` on sidecar and CERT. +- Job does **not** hash file bytes for blake3; it only passes through an + upstream digest. +- Sidecar always stamps `"helper_version": HelperVersion`. +- **Hold ≠ evidence.** Local hold / pending ids are queue handles only. + Certificates, “Download proof”, and legal claims are allowed only for + final / already-registered states (`statuslang.IsEvidence`). Standing + copy: `statuslang.EvidenceNote`. + +## statuslang notify titles + +Source: [`internal/statuslang`](../internal/statuslang/status.go). Tray, +menu bar, and helper balloons must use these short titles (not free-form +strings): + +| State key | Notify title | +|-----------|--------------| +| `held` / `signin` | `Sign in to finish timestamp` | +| `final` / `completed` / `ok` | `Final receipt ready` | +| (ready path) | `Printer ready` | +| `pending` | `Pending receipt` | +| `queued` | `Queued offline` | +| `hashing` | `Hashing on device…` | +| `provisional` | `Stamped, awaiting blockchain` | +| `failed` / `action` | failed / action chip strings | +| `existing` | `Already registered` | + +Helpers: + +- `NotifyTitle(state)`, `NotifyBody(state, title, extra)` — for held/pending, + `extra` is a **local hold id** (never a receipt). +- `NotifyHeldJobs(n)` — cancel / still-waiting banner. +- `TrayHeadline` / `TrayDetail` — persistent tray line (held count, key OK, + helper up, package version on Windows scripts). + +Windows `verae-tray.ps1` mirrors the same brand strings inline; keep them +in sync with `statuslang` when labels change. + +## IPP: GET status pure; POST print separate + +Same loopback port hosts two concerns. They must not couple. + +| Method / path | Role | Consumers | +|---------------|------|-----------| +| **GET** `/status` | JSON helper snapshot (held, key, health) | tray, menubar, `tray-status` | +| **GET** `/queue` | HTML job queue (PT-04/W4) | tray “Open queue”, browser | +| **GET** `/` | Health | probes | +| **POST** (IPP Print-Job / send-document) | Actual print capture → stamp pipeline | OS print spooler only | + +Constraints: + +- Tray / menubar / install scripts **GET only**. No IPP POST, no + `Print-Job`, no document send from presence UI. +- `serve` wires `ServeQueue` / `ServeStatus` as extra handlers beside the + IPP server; **POST remains pure IPP** so Windows/macOS print clients are + unaffected (`cmd/verae-print/serve.go`). +- Smoke `platform/smoke-packaging-metadata.sh` checks tray scripts for + accidental IPP POST coupling. + +## Verification + +```sh +# From apps/PrintToVeraeTimeStamp +./platform/smoke-packaging-metadata.sh +go test ./cmd/verae-print -count=1 -run 'Menubar|Packaging|TrayStartmenu|FindRepo' +go test ./internal/job ./internal/pdfcert ./internal/statuslang -count=1 +``` + +Expect: HelperVersion match, no elevated MSI path required, IPP pure on +tray/menubar assets. + +## Related paths + +| Path | Notes | +|------|--------| +| `internal/job/job.go` | `HelperVersion`, sidecar digests | +| `internal/pdfcert/` | CERT-01 build + multihash helpers | +| `internal/statuslang/` | Brand notify titles + evidence rules | +| `cmd/verae-print/serve.go` | IPP + GET `/queue` `/status` | +| `cmd/verae-print/traystatus.go` | `tray-status` CLI + HTTP handlers | +| `cmd/verae-print/menubar.go` | cross-platform menubar install | +| `cmd/verae-print/pending.go` | pending queue HTML | +| `platform/windows/scripts/` | tray / Startup / Start Menu | +| `platform/macos/menubar/` | Swift menubar + LaunchAgent + `.app` | +| `platform/macos/pkg/build-pkg.sh` | optional signed `.pkg` (certs required) | +| `platform/smoke-packaging-metadata.sh` | A4 packaging smoke |