Files
ctms/docs/guides/client-release.md
T
2026-07-09 09:30:44 +08:00

6.9 KiB

CTMS Web and Desktop Release Guide

Release Unit

CTMS uses one repository, one promotion path, and one product version. Web and Desktop are build targets from the same source commit, not separately versioned products.

The release identity consists of:

  • semantic version, for example 1.8.0
  • Git tag, for example v1.8.0
  • full Git commit SHA
  • build channel: dev, main, or release
  • client type: web or desktop

Runtime Boundary

Shared Vue business code lives under frontend/src/. Platform decisions are exposed through frontend/src/runtime/index.ts.

The runtime contract currently provides:

  • API base URL resolution
  • Web, macOS, Windows, and Linux runtime identification
  • app version, source commit, build channel, and client type metadata
  • explicit capability flags
  • Desktop server address configuration
  • secure session storage
  • file picker/save/open adapters
  • desktop system notification adapters
  • desktop updater adapters

Business modules must use this public runtime entry point. They must not inspect Tauri globals or import Tauri packages directly. Native files, notifications, secure session storage, and automatic updates must remain behind frontend/src/runtime/ and explicit capability flags.

Version Change

Update every client manifest with one command:

cd frontend
npm run version:set -- 1.8.0
npm run version:check

This synchronizes:

  • frontend/package.json
  • frontend/package-lock.json
  • frontend/src-tauri/tauri.conf.json
  • frontend/src-tauri/Cargo.toml
  • frontend/src-tauri/Cargo.lock

Manual edits that leave these files inconsistent fail CI.

Stabilization Gates

Client release candidates must pass the shared Web checks and the Desktop release/security gate before promotion:

cd frontend
npm run version:check
npm run release:env:check
npm run runtime:check
npm run desktop:release:check
npm run ui:contract
npm run type-check
npm run test:unit
npm run build
npm run desktop:build:app

release:env:check verifies build channel and commit metadata, and can be made strict for signed Desktop builds with REQUIRE_DESKTOP_SIGNING=true. desktop:release:check statically verifies the Tauri bundle, updater public key, CSP, capability scopes, command allowlist, query-token ban, generic system notification boundary, CI gate coverage, and secure session token boundary. The full manual release, security, regression, and Desktop UX checklist lives in docs/audits/desktop-release-stabilization-checklist.md.

Promotion

  1. Merge feature branches into dev.
  2. Require the shared client/Web and macOS Desktop CI jobs to pass.
  3. Promote the accepted scope from dev to main.
  4. Set the release version and complete regression testing on main.
  5. Promote main to release.
  6. Create the matching vX.Y.Z tag on the accepted release commit.
  7. Build both Web and Desktop artifacts from that exact tag.

Build metadata is injected by CI:

VITE_BUILD_CHANNEL=release
VITE_BUILD_COMMIT="$(git rev-parse HEAD)"

These values support diagnostics but do not replace the semantic version.

Desktop Updater

Formal Desktop release builds must use Tauri updater signatures. The application embeds the updater public key in frontend/src-tauri/tauri.conf.json; the private key must live only in the organization key vault or CI secret store.

Runtime update checks derive the feed from the currently configured CTMS origin:

/desktop-updates/stable/latest.json

Production update feeds must use HTTPS. Local update testing may use HTTP only for localhost, 127.0.0.1, or ::1.

The release pipeline must:

  1. build from the accepted release tag and commit;
  2. build macOS Universal desktop artifacts;
  3. sign and notarize the macOS app;
  4. produce updater artifacts and .sig files with the updater private key;
  5. generate latest.json and a checksum manifest with npm run desktop:update-feed:create;
  6. verify the feed with npm run desktop:update-feed:check -- --feed <release-dir>/latest.json --artifacts-dir <release-dir>;
  7. upload immutable artifacts first;
  8. atomically replace latest.json last.

For Universal macOS artifacts, latest.json must provide both darwin-aarch64 and darwin-x86_64 entries pointing at the same Universal update package.

The signed release candidate workflow lives at .github/workflows/desktop-release-candidate.yml. It must be run from a matching vX.Y.Z tag and produces a verified release directory as a GitHub artifact. That artifact is still only a release candidate; the release owner must upload immutable files to the production download origin and replace latest.json atomically after validation.

Windows Build Readiness

Second-phase Windows work is limited to CI compatibility validation. A windows-latest x64 NSIS build may be produced for verification, but it is not a formal deliverable until Windows code signing and release support are approved.

Windows validation must cover:

  • WebView2 runtime prerequisite behavior;
  • user-level installer assumptions;
  • Windows Credential Manager session storage;
  • path handling and temporary file cleanup;
  • notification and updater compilation;
  • future code-signing requirements.

The manual internal Windows validation workflow lives at .github/workflows/desktop-windows-internal.yml. It is workflow_dispatch only, runs on windows-latest, injects VITE_BUILD_CHANNEL and VITE_BUILD_COMMIT from the selected branch context, executes the shared client and Desktop safety gates, builds an unsigned NSIS installer with updater artifacts disabled, and uploads the .exe plus SHA256SUMS.txt as a GitHub Actions artifact. This workflow is for internal compatibility verification only; it must not generate latest.json, update feeds, signed release directories, or formal Windows release artifacts.

Required Checks

cd frontend
npm ci
npm run version:check
export VITE_BUILD_CHANNEL=release
export VITE_BUILD_COMMIT="$(git rev-parse HEAD)"
npm run release:env:check
npm run runtime:check
npm run desktop:release:check
npm run ui:contract
npm run type-check
npm run test:unit
npm run build
npm run desktop:build:app
export TAURI_SIGNING_PRIVATE_KEY="$UPDATER_PRIVATE_KEY"
export TAURI_SIGNING_PRIVATE_KEY_PASSWORD="$UPDATER_PRIVATE_KEY_PASSWORD"
export REQUIRE_DESKTOP_SIGNING=true
npm run release:env:check
npm run desktop:release-readiness:check
npm run desktop:build:macos-release -- --ci
npm run desktop:update-feed:create -- --artifact <CTMS.app.tar.gz> --base-url <versioned-https-artifact-prefix> --output-dir <release-dir>
npm run desktop:update-feed:check -- --feed <release-dir>/latest.json --artifacts-dir <release-dir>

The Desktop build must run on macOS for the current first-phase target. A signed or notarized public release additionally requires the Apple credentials defined by the release owner. A formal second-phase desktop release also requires the updater signing key; unsigned internal builds are not formal distributions.