From 14b1668ebe121533bf8014b408cd13e380a154d7 Mon Sep 17 00:00:00 2001 From: lucaronin Date: Thu, 28 May 2026 10:18:45 +0200 Subject: [PATCH] fix: unblock alpha release without windows cert --- .github/workflows/release-build-artifacts.yml | 41 ++++++++++++++++--- .github/workflows/release-stable.yml | 1 + .github/workflows/release.yml | 2 +- docs/ABSTRACTIONS.md | 2 +- docs/ARCHITECTURE.md | 6 +-- docs/adr/0132-alpha-authenticode-soft-gate.md | 25 +++++++++++ docs/adr/README.md | 1 + 7 files changed, 67 insertions(+), 11 deletions(-) create mode 100644 docs/adr/0132-alpha-authenticode-soft-gate.md diff --git a/.github/workflows/release-build-artifacts.yml b/.github/workflows/release-build-artifacts.yml index 20ce7588..0c406fa4 100644 --- a/.github/workflows/release-build-artifacts.yml +++ b/.github/workflows/release-build-artifacts.yml @@ -13,6 +13,10 @@ on: upload_macos_dmg: required: true type: boolean + require_windows_authenticode: + required: false + type: boolean + default: true env: # Bump this when Tauri/Rust target artifacts capture stale absolute paths. @@ -412,6 +416,7 @@ jobs: (Get-Content "src-tauri/Cargo.toml") -replace '^version = ".*"$', "version = `"$version`"" | Set-Content "src-tauri/Cargo.toml" - name: Validate Windows release env + id: windows-signing shell: bash env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} @@ -420,6 +425,7 @@ jobs: WINDOWS_CODE_SIGNING_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CODE_SIGNING_CERTIFICATE_PASSWORD }} WINDOWS_CERTIFICATE: ${{ secrets.WINDOWS_CERTIFICATE }} WINDOWS_CERTIFICATE_PASSWORD: ${{ secrets.WINDOWS_CERTIFICATE_PASSWORD }} + REQUIRE_WINDOWS_AUTHENTICODE: ${{ inputs.require_windows_authenticode }} run: | for name in TAURI_SIGNING_PRIVATE_KEY TAURI_KEY_PASSWORD; do if [ -z "${!name}" ]; then @@ -427,16 +433,33 @@ jobs: exit 1 fi done - if [ -z "$WINDOWS_CODE_SIGNING_CERTIFICATE" ] && [ -z "$WINDOWS_CERTIFICATE" ]; then - echo "::error::WINDOWS_CODE_SIGNING_CERTIFICATE or WINDOWS_CERTIFICATE is required to Authenticode-sign Windows installers." - exit 1 + + has_certificate=false + has_password=false + if [ -n "$WINDOWS_CODE_SIGNING_CERTIFICATE" ] || [ -n "$WINDOWS_CERTIFICATE" ]; then + has_certificate=true fi - if [ -z "$WINDOWS_CODE_SIGNING_CERTIFICATE_PASSWORD" ] && [ -z "$WINDOWS_CERTIFICATE_PASSWORD" ]; then - echo "::error::WINDOWS_CODE_SIGNING_CERTIFICATE_PASSWORD or WINDOWS_CERTIFICATE_PASSWORD is required to import the Windows signing certificate." + if [ -n "$WINDOWS_CODE_SIGNING_CERTIFICATE_PASSWORD" ] || [ -n "$WINDOWS_CERTIFICATE_PASSWORD" ]; then + has_password=true + fi + + if [ "$has_certificate" != "$has_password" ]; then + echo "::error::Windows Authenticode signing is partially configured. Set both certificate and password secrets, or remove both for unsigned alpha Windows artifacts." exit 1 fi + if [ "$has_certificate" = "true" ]; then + echo "authenticode_available=true" >> "$GITHUB_OUTPUT" + elif [ "$REQUIRE_WINDOWS_AUTHENTICODE" = "true" ]; then + echo "::error::WINDOWS_CODE_SIGNING_CERTIFICATE or WINDOWS_CERTIFICATE is required to Authenticode-sign Windows installers." + exit 1 + else + echo "::warning::Windows Authenticode certificate secrets are not configured. Building alpha Windows artifacts without Authenticode signatures; Tauri updater signatures are still required." + echo "authenticode_available=false" >> "$GITHUB_OUTPUT" + fi + - name: Prepare Windows Authenticode signing + if: ${{ steps.windows-signing.outputs.authenticode_available == 'true' }} shell: pwsh env: WINDOWS_CODE_SIGNING_CERTIFICATE: ${{ secrets.WINDOWS_CODE_SIGNING_CERTIFICATE }} @@ -450,6 +473,7 @@ jobs: run: ./.github/scripts/configure-windows-authenticode.ps1 - name: Build Tauri app (Windows bundles) + shell: pwsh env: TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY }} TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }} @@ -459,9 +483,14 @@ jobs: VITE_POSTHOG_KEY: ${{ secrets.VITE_POSTHOG_KEY }} VITE_POSTHOG_HOST: ${{ secrets.VITE_POSTHOG_HOST }} run: | - pnpm tauri build --target x86_64-pc-windows-msvc --bundles nsis --config src-tauri/tauri.windows-signing.conf.json + if ("${{ steps.windows-signing.outputs.authenticode_available }}" -eq "true") { + pnpm tauri build --target x86_64-pc-windows-msvc --bundles nsis --config src-tauri/tauri.windows-signing.conf.json + } else { + pnpm tauri build --target x86_64-pc-windows-msvc --bundles nsis + } - name: Validate Windows Authenticode signatures + if: ${{ steps.windows-signing.outputs.authenticode_available == 'true' }} shell: pwsh run: | $expectedThumbprint = $env:WINDOWS_CODE_SIGNING_CERTIFICATE_THUMBPRINT diff --git a/.github/workflows/release-stable.yml b/.github/workflows/release-stable.yml index bd843cad..c25d88ba 100644 --- a/.github/workflows/release-stable.yml +++ b/.github/workflows/release-stable.yml @@ -67,6 +67,7 @@ jobs: version: ${{ needs.version.outputs.version }} macos_bundles: "" upload_macos_dmg: true + require_windows_authenticode: true secrets: inherit # ───────────────────────────────────────────────────────────── diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1f17e32a..dc35f7b7 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -8,7 +8,6 @@ on: - ".husky/**" - ".github/workflows/deploy-docs.yml" - ".github/workflows/release.yml" - - ".github/workflows/release-build-artifacts.yml" - "site/**" concurrency: @@ -128,6 +127,7 @@ jobs: version: ${{ needs.version.outputs.version }} macos_bundles: app upload_macos_dmg: false + require_windows_authenticode: false secrets: inherit # ───────────────────────────────────────────────────────────── diff --git a/docs/ABSTRACTIONS.md b/docs/ABSTRACTIONS.md index 1f4ae986..83b4da4e 100644 --- a/docs/ABSTRACTIONS.md +++ b/docs/ABSTRACTIONS.md @@ -941,6 +941,6 @@ Managed by `useSettings` hook and `SettingsPanel` component. `theme_mode` is ins - **`download_and_install_app_update`** — Channel-aware download/install with streamed progress events. ### CI/CD -- **`.github/workflows/release.yml`** — Alpha prereleases from every push to `main` using calendar-semver technical versions (`YYYY.M.D-alpha.N`) and clean `Alpha YYYY.M.D.N` release names. GitHub alpha tags zero-pad the prerelease sequence (`alpha-vYYYY.M.D-alpha.NNNN`) so GitHub release ordering stays chronological while the shipped app version remains `YYYY.M.D-alpha.N`. Publishes `alpha/latest.json` with macOS Apple Silicon/Intel, Linux x64, and Windows x64 updater entries, then refreshes the legacy `latest.json` / `latest-canary.json` aliases to the alpha feed. The Windows job imports the CI code-signing certificate, builds NSIS with a generated Tauri Authenticode signing config, and verifies the app executable plus installer signatures with `Get-AuthenticodeSignature` before upload. The Linux job uses Tauri's stock linuxdeploy AppImage output plugin and validates that installer and updater-signature artifacts exist before upload. The docs/release Pages job reads the stable manifest from the latest stable release asset instead of copying the live Pages URL, uploads the built site as a Pages artifact, and deploys it with GitHub's official Pages action so the public updater JSON changes as part of the release workflow. macOS release assets use `Tolaria__macOS_Silicon` and `Tolaria__macOS_Intel` base names. Packaged builds pass the computed version as `VITE_SENTRY_RELEASE`, which is retained as a diagnostic build-version tag but not registered as a normal Sentry release for alpha builds. +- **`.github/workflows/release.yml`** — Alpha prereleases from every push to `main` using calendar-semver technical versions (`YYYY.M.D-alpha.N`) and clean `Alpha YYYY.M.D.N` release names. GitHub alpha tags zero-pad the prerelease sequence (`alpha-vYYYY.M.D-alpha.NNNN`) so GitHub release ordering stays chronological while the shipped app version remains `YYYY.M.D-alpha.N`. Publishes `alpha/latest.json` with macOS Apple Silicon/Intel, Linux x64, and Windows x64 updater entries, then refreshes the legacy `latest.json` / `latest-canary.json` aliases to the alpha feed. The Windows job builds NSIS with Tauri updater signatures and uses Authenticode signing plus `Get-AuthenticodeSignature` verification when CI certificate secrets are configured; stable remains the strict channel for mandatory Authenticode enforcement. The Linux job uses Tauri's stock linuxdeploy AppImage output plugin and validates that installer and updater-signature artifacts exist before upload. The docs/release Pages job reads the stable manifest from the latest stable release asset instead of copying the live Pages URL, uploads the built site as a Pages artifact, and deploys it with GitHub's official Pages action so the public updater JSON changes as part of the release workflow. Changes to the shared artifact workflow are not ignored by the alpha trigger, so release-pipeline fixes produce a fresh alpha run. macOS release assets use `Tolaria__macOS_Silicon` and `Tolaria__macOS_Intel` base names. Packaged builds pass the computed version as `VITE_SENTRY_RELEASE`, which is retained as a diagnostic build-version tag but not registered as a normal Sentry release for alpha builds. - **`.github/workflows/release-stable.yml`** — Stable releases from `stable-vYYYY.M.D` tags. Publishes `stable/latest.json`, macOS Apple Silicon and Intel DMG/updater artifacts, Authenticode-signed Windows x64 installers plus Tauri-signed updater bundles, Linux x86_64 `.deb` / `.rpm` / AppImage artifacts, and a static public download page that starts selected non-Windows installers without replacing the page with a blank download navigation. Windows visitors see an explicit signed-installer action and managed-device approval guidance instead of an automatic download. Linux visitors default to the AppImage target while the page exposes RPM as a manual Linux package option when the stable release includes one. The Linux job uses the same stock Tauri/linuxdeploy AppImage packaging and artifact validation as alpha releases. The Pages job reads the alpha manifest from the latest alpha release asset instead of copying the live Pages URL, uploads the built site as a Pages artifact, and deploys it with GitHub's official Pages action so stable and alpha manifests stay fresh. Stable macOS DMG/updater assets use the same `Tolaria__macOS_Silicon` and `Tolaria__macOS_Intel` base names. Packaged builds pass the computed stable version as `VITE_SENTRY_RELEASE`, which is registered as Sentry's release. - **Beta cohorts** are handled in PostHog targeting only. There is no beta updater feed. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 42308566..54a5f90d 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -941,9 +941,9 @@ push to main → tauri build --target x86_64-unknown-linux-gnu --bundles deb,rpm,appimage → verify Linux installer and updater-signature artifacts exist → upload .deb, .rpm, .AppImage, and signed Linux updater bundles - → pnpm install, stamp version, import the Windows code-signing certificate - → tauri build --target x86_64-pc-windows-msvc --bundles nsis with Authenticode signing config - → verify the Windows app executable and installer Authenticode signatures with Get-AuthenticodeSignature + → pnpm install, stamp version, import the Windows code-signing certificate when configured + → tauri build --target x86_64-pc-windows-msvc --bundles nsis, using the Authenticode signing config when certificate secrets exist + → verify the Windows app executable and installer Authenticode signatures with Get-AuthenticodeSignature when Authenticode is configured → upload NSIS installer, optional MSI artifacts, and signed Windows updater bundles → release job: → generate alpha-latest.json with darwin-aarch64, darwin-x86_64, Linux, and Windows updater URLs diff --git a/docs/adr/0132-alpha-authenticode-soft-gate.md b/docs/adr/0132-alpha-authenticode-soft-gate.md new file mode 100644 index 00000000..b9b99251 --- /dev/null +++ b/docs/adr/0132-alpha-authenticode-soft-gate.md @@ -0,0 +1,25 @@ +--- +type: ADR +id: "0132" +title: "Alpha Authenticode soft gate" +status: active +date: 2026-05-28 +amends: "0130" +--- + +## Context + +ADR 0130 made Windows Authenticode signing mandatory for release installers. That is still the right requirement for stable promotions, but the repository does not yet have the Windows code-signing certificate secrets needed by CI. Because alpha releases run on every push to `main`, requiring those secrets there broke the continuous alpha channel before the certificate provisioning work was complete. + +## Decision + +**Alpha Windows artifacts keep building when Authenticode certificate secrets are absent; stable Windows artifacts still require Authenticode signing.** + +- The shared release artifact workflow accepts `require_windows_authenticode`. +- Alpha passes `false`, emits a workflow warning when certificate secrets are absent, and still requires Tauri updater signatures. +- Stable passes `true` and fails before building Windows artifacts unless certificate and password secrets are configured. +- When certificate secrets are present, both channels use the generated Tauri Authenticode config and verify Windows executable/installer signatures before upload. + +## Consequences + +The alpha updater channel remains live while Windows certificate provisioning is underway. Stable releases continue to enforce the Windows trust policy from ADR 0130 before public promotion. Once the certificate secrets are configured, alpha builds automatically regain Authenticode signing without another workflow change. diff --git a/docs/adr/README.md b/docs/adr/README.md index 4146ed92..75f5e4f6 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -183,3 +183,4 @@ proposed → active → superseded | [0129](0129-tolaria-vault-item-deep-links.md) | Tolaria vault item deep links | active | | [0130](0130-windows-authenticode-release-signing.md) | Windows Authenticode signing for release installers | active | | [0131](0131-reusable-release-artifact-build-workflow.md) | Reusable release artifact build workflow | active | +| [0132](0132-alpha-authenticode-soft-gate.md) | Alpha Authenticode soft gate | active |