Stable releases are performed only by the checked-in GitHub Actions workflows. Local validation never publishes, deploys, signs, or creates a GitHub release.
.github/workflows/ci.yml runs:
- ESLint, TypeScript typecheck, unit tests, builds, workflow contract tests;
- isolated npm tarball install and
folder-syncexecution; - real PostgreSQL 16 migration/API/desktop seam integration;
- Rust
fmt,clippy -D warnings, and tests; - Tauri compile matrices for macOS Universal, Windows x64, and Windows ARM64.
Windows ARM64 uses GitHub's native windows-11-arm runner. CI uses --no-bundle for compile coverage; it does not create an unsigned installer.
Validate workflow syntax/contracts without publishing:
pnpm validate:workflows
pnpm test:releaseRun release-desktop-candidate.yml manually from reviewed master with confirmation build-rootline-candidate. The protected desktop-production environment and the same Apple, Windows, updater, Authentik, and API values used by stable release are mandatory, so candidate testing exercises the real signing and hosted-profile configuration.
The default internal channel uploads signed/notarized workflow artifacts only. After internal QA passes, rerun with channel public-beta and a new tag matching v2.0.0-beta.N; the workflow builds that SemVer prerelease, verifies every platform signature, and creates a GitHub prerelease. It does not publish latest.json or change the stable updater channel. A beta installation can upgrade after the signed 2.0.0 stable updater manifest is published.
Use this sequence before stable release: internal signed candidate, public beta, then the API → npm → desktop stable train. Never promote an artifact from an unreviewed branch or reuse an existing beta tag.
release-npm.yml publishes only the public folder-structure-sync package. It runs only from the existing v2.0.0 tag (with an additional exact confirmation for manual runs), checks the package version, and stops if the protected npm-production environment secret NPM_TOKEN is missing. An unprivileged job reruns quality/unit gates, installs the packed CLI in isolation, and uploads the exact tarball plus an independent checksum output. A minimal protected npm-production job verifies that checksum and packed identity, then exposes NPM_TOKEN only to npm publish with provenance and public access. @rootline/core and @rootline/contracts remain private workspace packages bundled into the CLI; they are never published independently.
Required external gate: protected npm-production environment secret NPM_TOKEN with publish access, plus approval for that environment. Never configure this credential as a repository secret.
release-api.yml requires the existing v2.0.0 tag, an exact manual confirmation, and every production database/auth/deployment secret. It uses a digest-pinned Node base and refuses to run if GHCR tag rootline-api:2.0.0 already exists. It pushes a unique candidate tag, applies the checked-in migrations, then calls the HTTPS deployment webhook with the resulting immutable digest and unique workflow build identity. It polls HTTPS /healthz until that exact identity is live. Only after health succeeds does it promote that verified digest to rootline-api:2.0.0; a failed attempt leaves stable identity unused and safely retryable. A healthy response from an older replica cannot pass the gate.
Required external gates: ROOTLINE_API_DATABASE_URL, ROOTLINE_API_DEPLOY_WEBHOOK_URL, ROOTLINE_API_DEPLOY_TOKEN, ROOTLINE_API_BASE_URL, ROOTLINE_JWT_ISSUER, ROOTLINE_JWT_AUDIENCE, ROOTLINE_JWT_JWKS_B64, GHCR permissions, and api-production approval. PostgreSQL TLS/backup and provider runtime configuration are operator responsibilities.
release-desktop.yml runs only from the existing v2.0.0 tag. Before any platform build, preflight signs a challenge with the configured Tauri updater private key/password and verifies it with the configured public key; an invalid or mismatched keypair blocks the release. macOS Universal is Developer ID signed, notarized, and stapled. Windows x64 and ARM64 installer/updater executables are Authenticode signed and timestamped. Tauri updater artifacts cover the default darwin-aarch64, darwin-x86_64, windows-x86_64, and windows-aarch64 runtime keys; latest.json is generated from their non-empty .sig files. Release publication occurs only after code-signature/staple verification succeeds.
Required external gates:
- Apple:
APPLE_CERTIFICATE,APPLE_CERTIFICATE_PASSWORD,APPLE_SIGNING_IDENTITY,APPLE_ID,APPLE_PASSWORD,APPLE_TEAM_ID,APPLE_KEYCHAIN_PASSWORD. - Windows:
WINDOWS_CERTIFICATE,WINDOWS_CERTIFICATE_PASSWORD. - Updater:
TAURI_SIGNING_PRIVATE_KEY,TAURI_SIGNING_PRIVATE_KEY_PASSWORD, and matching public environment variableTAURI_UPDATER_PUBLIC_KEY; custody and rotation must be defined before the first stable release. - Hosted profile build variables:
VITE_AUTHENTIK_ISSUER,VITE_AUTHENTIK_CLIENT_ID,VITE_ROOTLINE_SYNC_API. - Protected
desktop-productionapproval and a reviewedv2.0.0git tag.
Missing values produce an actionable preflight error. Do not replace a missing production identity with ad-hoc signing, an empty updater key, --skip-stapling, or an unsigned artifact.
After an authorized workflow completes, verify npm provenance and a clean install; image digest, migration log, and HTTPS health; Apple signature/notarization/staple; Windows Authenticode status/timestamp; updater URLs, checksums, and signatures; and that portal wording reflects actual availability. If any platform fails, keep the release blocked rather than publishing a partial stable claim.
Published versions and migrations are immutable. Fix forward with a new version and migration. Revoke compromised installers/updater keys through the release provider and rotate keys; never overwrite 2.0.0 with different bytes.
- Operations - API rollout and incidents.
- Security policy - Stable supply-chain controls.
- Privacy - Data boundaries that releases must preserve.