docs: release-packaging guide + track distribution (BL-P1..P4)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
14
CLAUDE.md
14
CLAUDE.md
@@ -95,14 +95,14 @@ py -m venv .venv
|
||||
.venv\Scripts\python -m pytest tests/core/test_codecs.py::test_name # one test
|
||||
.venv\Scripts\python -m ruff check cim_suite tests
|
||||
|
||||
# Build standalone exe (one-folder) + verify it actually booted
|
||||
.venv\Scripts\pyinstaller --noconfirm --distpath packaging\dist --workpath packaging\build packaging\suite.spec
|
||||
$env:SUITE_SELFTEST="1"; .\packaging\dist\CIM-Service-Suite\CIM-Service-Suite.exe --module da12 --simulate; echo "exit=$LASTEXITCODE"; Remove-Item Env:\SUITE_SELFTEST
|
||||
# Build BOTH distribution artifacts (per-user installer + portable zip) in one shot.
|
||||
# Version is single-sourced from cim_suite.__version__. The installer needs Inno Setup 6
|
||||
# (without it, build.ps1 warns and produces the portable zip only). Code signing is gated
|
||||
# on $env:CIM_SIGN_CERT (see docs/RELEASE-PACKAGING.md); skipped if unset.
|
||||
powershell -ExecutionPolicy Bypass -File packaging\build.ps1
|
||||
|
||||
# Build installer (needs Inno Setup 6). Version is single-sourced from pyproject.toml,
|
||||
# so pass it in (else the installer falls back to the 0.0.0-dev sentinel):
|
||||
$v = .venv\Scripts\python -c "import cim_suite; print(cim_suite.__version__)"
|
||||
& "C:\Program Files (x86)\Inno Setup 6\ISCC.exe" /DAppVersion=$v packaging\installer.iss
|
||||
# Verify the frozen exe actually booted (GUI app — use Start-Process -Wait for the exit code)
|
||||
$env:SUITE_SELFTEST="1"; $p = Start-Process .\packaging\dist\CIM-Service-Suite\CIM-Service-Suite.exe -ArgumentList "--module","da12","--simulate" -Wait -PassThru; echo "exit=$($p.ExitCode)"; Remove-Item Env:\SUITE_SELFTEST
|
||||
```
|
||||
|
||||
The whole test suite runs headless with no hardware (`SimulatedStation` speaks the
|
||||
|
||||
@@ -118,6 +118,41 @@ no migration.
|
||||
|
||||
---
|
||||
|
||||
## Packaging / distribution
|
||||
|
||||
### BL-P1 — End-user distribution (per-user installer + portable, signing-ready) · DONE
|
||||
*Completed 2026-06-08.*
|
||||
The suite now ships two artifacts a non-admin user can run on a locked-down laptop:
|
||||
a **per-user installer** (`PrivilegesRequired=lowest` → `%LOCALAPPDATA%\Programs`, no
|
||||
UAC) and a **portable zip** (unzip-and-run), both built in one shot by
|
||||
`packaging\build.ps1`. The exe carries the brand icon (`packaging\icon.ico`, generated
|
||||
from `docs/samples/icon.png`) and version metadata. Code signing is wired into the
|
||||
build but **inert** until `CIM_SIGN_CERT`/`CIM_SIGN_PARAMS` are set (OV / Azure Trusted
|
||||
Signing — not EV; see `docs/RELEASE-PACKAGING.md`). A bundled `READ-ME-FIRST.txt` walks
|
||||
users through the SmartScreen warning. Pillow is a build-only dep (`make_icon.py`) and is
|
||||
excluded from the frozen app.
|
||||
- **Spec/plan:** `docs/superpowers/specs/2026-06-08-end-user-distribution-design.md`,
|
||||
`docs/superpowers/plans/2026-06-08-end-user-distribution.md`.
|
||||
|
||||
### BL-P2 — Buy + enable a code-signing certificate · P1 · TODO
|
||||
*Added 2026-06-08.*
|
||||
Until signed, SmartScreen warns on first run and the strictest (AppLocker/WDAC) shops
|
||||
cannot run the app at all. Acquire an OV cert or enrol in Azure Trusted Signing, then
|
||||
follow the turn-on checklist in `docs/RELEASE-PACKAGING.md` (the build hooks already
|
||||
exist). Tracked separately because it needs a purchasing decision, not code.
|
||||
|
||||
### BL-P3 — Auto-update checker · P3 · TODO
|
||||
*Added 2026-06-08.*
|
||||
Self-serve users have no update path today (the launcher only shows a "What's new"
|
||||
dialog). A future spec: check for a newer published version and prompt to download.
|
||||
|
||||
### BL-P4 — Screenshots in the run guide · P3 · TODO
|
||||
*Added 2026-06-08.*
|
||||
`packaging\READ-ME-FIRST.txt` is text-only. A screenshot-illustrated version of the
|
||||
SmartScreen "More info → Run anyway" click-path would help non-technical users.
|
||||
|
||||
---
|
||||
|
||||
## Robustness & cleanup
|
||||
|
||||
### BL-1 — Graceful shutdown on app close · P2 · DONE
|
||||
|
||||
@@ -35,6 +35,13 @@ failure, and both controllers bridge it to `connectionChanged` — the label fli
|
||||
"Disconnected" and the pill greys, same as a deliberate stop. Report-only; auto-reconnect
|
||||
is filed as BL-9. See BL-2/BL-5 (DONE).
|
||||
|
||||
**End-user distribution (BL-P1, 2026-06-08):** the suite now builds two artifacts a
|
||||
non-admin user can run on a locked-down laptop — a **per-user no-admin installer**
|
||||
(`%LOCALAPPDATA%\Programs`) and a **portable zip** — via `packaging\build.ps1`. The exe
|
||||
carries the brand icon + version metadata, and a `READ-ME-FIRST.txt` walks users past the
|
||||
SmartScreen warning. Code signing is wired but **inert** pending a certificate purchase
|
||||
(**BL-P2** — OV / Azure Trusted Signing, not EV). See `docs/RELEASE-PACKAGING.md`.
|
||||
|
||||
App-wide **serial → model recognition + channel grouping** is now implemented (BL-D1
|
||||
DONE). `cim_suite/core/sensor_models.py` maps any sensor serial to a model name and
|
||||
channel type via prefix lookup, and clusters related channels by shared serial body.
|
||||
|
||||
87
docs/RELEASE-PACKAGING.md
Normal file
87
docs/RELEASE-PACKAGING.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Release packaging
|
||||
|
||||
How to build the distributable artifacts and (later) turn on code signing.
|
||||
|
||||
## Build both artifacts
|
||||
|
||||
Prerequisites: the dev env (`pip install -e ".[dev]"`) and — for the installer —
|
||||
**Inno Setup 6** at `C:\Program Files (x86)\Inno Setup 6\ISCC.exe` (or `ISCC.exe` on
|
||||
PATH).
|
||||
|
||||
```powershell
|
||||
powershell -ExecutionPolicy Bypass -File packaging\build.ps1
|
||||
```
|
||||
|
||||
Outputs (in `packaging\Output\`), version taken from `cim_suite.__version__`:
|
||||
|
||||
- `CIM-Service-Suite-<ver>-Setup.exe` — **per-user installer**. No admin/UAC; installs
|
||||
to `%LOCALAPPDATA%\Programs`, per-user Start-menu shortcut, HKCU uninstall entry.
|
||||
- `CIM-Service-Suite-<ver>-portable.zip` — **unzip-and-run**. No install, no registry,
|
||||
no admin. App data lives under `%LOCALAPPDATA%\CIMTechniques` either way.
|
||||
|
||||
Both wrap the same PyInstaller one-folder output, so they never drift. The end-user
|
||||
`READ-ME-FIRST.txt` is copied to the bundle root by the build, so it sits beside the
|
||||
exe in the zip and at `{app}` root after install.
|
||||
|
||||
**If Inno Setup is not installed**, `build.ps1` prints a warning, skips the installer,
|
||||
and produces only the portable zip — so the script still works on a plain dev machine.
|
||||
Install Inno Setup 6 to get the installer.
|
||||
|
||||
## The app icon
|
||||
|
||||
The icon everywhere (exe, installer, Start-menu shortcut, runtime window) is generated
|
||||
from `docs/samples/icon.png`. Regenerate the committed assets only when the art changes
|
||||
(needs Pillow, which is in the `dev` extras):
|
||||
|
||||
```powershell
|
||||
.venv\Scripts\python packaging\make_icon.py
|
||||
```
|
||||
|
||||
This writes `packaging\icon.ico` and `cim_suite\shell\resources\app_icon.png`. Pillow is
|
||||
a **build-time-only** dependency — `suite.spec` excludes `PIL` so it never ships in the
|
||||
frozen app.
|
||||
|
||||
## Code signing (not yet enabled)
|
||||
|
||||
The app currently ships **unsigned**, so Windows SmartScreen warns on first run
|
||||
(`packaging\READ-ME-FIRST.txt` tells users how to proceed). The strictest customer
|
||||
environments (AppLocker/WDAC "signed only") cannot run it until it is signed.
|
||||
|
||||
### Which certificate
|
||||
|
||||
Use an **OV** (Organization Validated) code-signing certificate, OR **Azure Trusted
|
||||
Signing** (Microsoft's cloud service — no physical token, CI-friendly; price out
|
||||
first). Do **not** buy EV: as of March 2024 EV no longer gives instant SmartScreen
|
||||
trust, and EV is only required for kernel-mode driver signing, which this app does not
|
||||
do. Even with OV, SmartScreen reputation builds with download volume — keep the **same**
|
||||
certificate across releases so reputation carries forward.
|
||||
|
||||
### Turning it on
|
||||
|
||||
Signing is already wired in `packaging\build.ps1` (it signs both the inner exe and the
|
||||
Setup.exe) and is gated on env vars, so it is a no-op until configured:
|
||||
|
||||
1. Acquire the OV cert / enrol in Azure Trusted Signing; install the token or HSM client.
|
||||
2. Set the build environment:
|
||||
- `CIM_SIGN_CERT=1`
|
||||
- `CIM_SIGN_PARAMS=<signtool cert-selection args>`, e.g.
|
||||
`/n "CIMTechniques, Inc."` (cert store by subject name) or
|
||||
`/f cert.pfx /p <password>` (file-based).
|
||||
3. Re-run `packaging\build.ps1`. It signs with SHA-256 + RFC-3161 timestamping
|
||||
(`http://timestamp.digicert.com`) so signatures stay valid after the cert expires.
|
||||
4. Verify: right-click each artifact → Properties → **Digital Signatures** shows
|
||||
"CIMTechniques, Inc."
|
||||
|
||||
## Self-test
|
||||
|
||||
Both the installed copy and the extracted-portable copy can be smoke-tested headlessly.
|
||||
Because the exe is a GUI-subsystem app, use `Start-Process -Wait -PassThru` to capture
|
||||
the exit code (a bare `&` call does not block on GUI apps):
|
||||
|
||||
```powershell
|
||||
$env:SUITE_SELFTEST="1"
|
||||
$p = Start-Process -FilePath "<path>\CIM-Service-Suite.exe" `
|
||||
-ArgumentList "--module","da12","--simulate" -Wait -PassThru
|
||||
"exit=$($p.ExitCode)" # 0 means it booted and self-quit
|
||||
Remove-Item Env:\SUITE_SELFTEST
|
||||
```
|
||||
Reference in New Issue
Block a user