Skip to content

chore(release): remove updater pubkey/endpoint override + gate signed artifacts#912

Merged
senamakel merged 1 commit into
tinyhumansai:mainfrom
senamakel:feat/updater-ci-gating
Apr 25, 2026
Merged

chore(release): remove updater pubkey/endpoint override + gate signed artifacts#912
senamakel merged 1 commit into
tinyhumansai:mainfrom
senamakel:feat/updater-ci-gating

Conversation

@senamakel
Copy link
Copy Markdown
Member

@senamakel senamakel commented Apr 25, 2026

Summary

Two related fixes to the release pipeline that together eliminate a real outage class ("bad keys" install failures) and stop PR/test builds from failing when they don't have signing secrets.

1. Drop the updater pubkey/endpoint override (the "bad keys" bug)

scripts/prepareTauriConfig.js was injecting plugins.updater.pubkey and plugins.updater.endpoints at build time from the UPDATER_PUBLIC_KEY / UPDATER_ENDPOINT / UPDATER_REPO env vars sourced from GitHub secrets/vars, on top of the static app/src-tauri/tauri.conf.json.

If the build-time UPDATER_PUBLIC_KEY ever drifted out of sync with TAURI_SIGNING_PRIVATE_KEY (e.g. one secret rotated, the other not) every signed installer was rejected by its own embedded pubkey at install time — surfacing as opaque "bad keys" errors.

The static tauri.conf.json already carries the canonical pubkey (7494D291DAB5B3E1 after #910) and endpoint (https://github.com/tinyhumansai/openhuman/releases/latest/download/latest.json), so removing the override leaves the build pointed at the same place — just without the silent-drift risk. Key rotations now go through commit + review, which is also better auditability.

2. Gate signed artifact creation behind WITH_UPDATER

Static bundle.createUpdaterArtifacts: false is now the safe default. PR build matrices (build.yml, build-windows.yml) and test.yml don't have access to TAURI_SIGNING_PRIVATE_KEY, so without this gate the bundler would either fail or silently emit unsigned .app.tar.gz / .sig files. Only release.yml sets WITH_UPDATER=true, which prepareTauriConfig.js then translates into bundle.createUpdaterArtifacts: true for that one pipeline.

Changes

  • scripts/prepareTauriConfig.js — removes the UPDATER_PUBLIC_KEY / UPDATER_ENDPOINT / UPDATER_REPO block. Function now only flips createUpdaterArtifacts when WITH_UPDATER=true and emits the Windows DigiCert signCommand when KEYPAIR_ALIAS is set.
  • app/src-tauri/tauri.conf.jsonbundle.createUpdaterArtifacts: truefalse (safe default).
  • .github/workflows/release.yml — drops UPDATER_PUBLIC_KEY validation; drops the UPDATER_PUBLIC_KEY / UPDATER_ENDPOINT / UPDATER_REPO env vars from the config-overrides step; drops the redundant WITH_UPDATER env from the tauri-build step (only prepareTauriConfig.js reads it, and that runs in the config-overrides step).
  • .github/workflows/build-windows.yml — drops the now-unused explicit WITH_UPDATER='false'.
  • scripts/ci-secrets.example.json — drops UPDATER_PUBLIC_KEY (secret) and UPDATER_ENDPOINT (var) to match the pruned env-var surface.

Action item for the repo owner before the next release

Confirm the GH Actions secret TAURI_SIGNING_PRIVATE_KEY (or legacy fallback UPDATER_PRIVATE_KEY) holds the private key matching the static pubkey 7494D291DAB5B3E1 (set by #910). If it still holds the old key, signing will succeed in CI but update.download_and_install() will fail signature verification on the user's machine.

You can safely delete these GH Actions secrets/vars too — nothing reads them anymore:

  • secrets.UPDATER_PUBLIC_KEY / vars.UPDATER_PUBLIC_KEY
  • vars.UPDATER_ENDPOINT

Test plan

  • node -e "import('./scripts/prepareTauriConfig.js').then(m => console.log(JSON.stringify(m.default(), null, 2)))" with no env → {}.
  • Same with WITH_UPDATER=true{ bundle: { createUpdaterArtifacts: true } }.
  • Same with KEYPAIR_ALIAS=foo{ bundle: { windows: { signCommand: '… --keypair-alias=foo …' } } }.
  • No remaining references to UPDATER_PUBLIC_KEY / UPDATER_ENDPOINT / UPDATER_REPO / UPDATER_GIST_URL outside of comments / changelogs.

Relationship to other open updater PRs

Summary by CodeRabbit

  • Refactor

    • Restructured build configuration script to focus exclusively on bundler overrides for improved separation of concerns.
  • Chores

    • Updated CI/CD workflows and reduced environment variable dependencies for improved maintainability.
    • Disabled automatic updater artifact creation in default builds.
    • Simplified example CI secrets configuration by removing deprecated updater-related entries.

… artifacts

The release pipeline was injecting `plugins.updater.pubkey` and
`plugins.updater.endpoints` from `UPDATER_PUBLIC_KEY` /
`UPDATER_ENDPOINT` env vars (sourced from GitHub secrets/vars) at build
time, on top of the static `app/src-tauri/tauri.conf.json`. This caused
a real outage class: if the build-time `UPDATER_PUBLIC_KEY` ever drifted
out of sync with the `TAURI_SIGNING_PRIVATE_KEY` secret used to sign
artifacts, every signed installer was rejected by its own embedded
pubkey at install time — surfacing as opaque "bad keys" errors.

Changes:

- `scripts/prepareTauriConfig.js`: drop the pubkey/endpoint override.
  The function now just flips `bundle.createUpdaterArtifacts: true`
  when `WITH_UPDATER=true` and emits the Windows DigiCert sign command
  when `KEYPAIR_ALIAS` is set. Pubkey + endpoint live in the static
  `app/src-tauri/tauri.conf.json` — rotate via commit + review, not
  silent secret swaps.
- `app/src-tauri/tauri.conf.json`: set `bundle.createUpdaterArtifacts:
  false` as the safe default. Workflows that don't have access to
  `TAURI_SIGNING_PRIVATE_KEY` (PR build matrices, the test workflow)
  inherit this and skip artifact signing entirely instead of failing.
  `release.yml` opts in via `WITH_UPDATER=true`.
- `.github/workflows/release.yml`: drop `UPDATER_PUBLIC_KEY` validation
  and the `UPDATER_PUBLIC_KEY` / `UPDATER_ENDPOINT` / `UPDATER_REPO` env
  vars from the config-overrides step. Drop the redundant
  `WITH_UPDATER` env from the tauri-build step (only the
  config-overrides step runs `prepareTauriConfig.js`).
- `.github/workflows/build-windows.yml`: drop the now-unused
  `WITH_UPDATER='false'` env var. Absence is the default.
- `scripts/ci-secrets.example.json`: drop `UPDATER_PUBLIC_KEY` and
  `UPDATER_ENDPOINT` to match the pruned env-var surface.

Action item before the next release: confirm the GH Actions secret
`TAURI_SIGNING_PRIVATE_KEY` (or fallback `UPDATER_PRIVATE_KEY`) holds
the private key matching the static pubkey
(`7494D291DAB5B3E1`, set by tinyhumansai#910).
@senamakel senamakel requested a review from a team April 25, 2026 05:26
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 25, 2026

📝 Walkthrough

Walkthrough

This pull request consolidates updater configuration management by removing environment variable injection from GitHub workflows, disabling updater artifact generation in the Tauri bundler configuration, and refactoring the configuration preparation script to only emit bundle overrides when necessary.

Changes

Cohort / File(s) Summary
GitHub Workflows
.github/workflows/build-windows.yml, .github/workflows/release.yml
Removed environment variable injection for updater-related config (BASE_URL, WITH_UPDATER, UPDATER_PUBLIC_KEY, UPDATER_ENDPOINT, UPDATER_REPO); workflows now rely on static Tauri configuration for updater settings.
Tauri Configuration & Build Scripts
app/src-tauri/tauri.conf.json, scripts/prepareTauriConfig.js, scripts/ci-secrets.example.json
Disabled updater artifact creation in bundler config (bundle.createUpdaterArtifacts: false); refactored script to return only bundle overrides instead of assembling full updater plugin configuration; removed corresponding CI secret and variable declarations from example template.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Poem

🐰 Hops through configs, ears held high,
Static secrets now rely,
No more env vars passed about,
Cleaner bundling—jobs, no doubt!
Artifacts at rest, config's true,
Simpler paths for all of you! 🎉

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: removing updater pubkey/endpoint overrides and gating signed artifact creation behind a WITH_UPDATER flag, directly matching the PR objectives.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
.github/workflows/release.yml (1)

393-396: ⚠️ Potential issue | 🟠 Major

Add a fail-fast keypair/parity verification step.

Line [393] verifies key presence only; it does not prove the secret key matches the static updater pubkey in app/src-tauri/tauri.conf.json. That can still produce installer/update signature rejection at runtime.

Suggested workflow hook
       - name: Validate signing prerequisites
         shell: bash
         env:
@@
           if [ -z "$TAURI_SIGNING_PRIVATE_KEY" ]; then
             echo "Missing TAURI_SIGNING_PRIVATE_KEY (or fallback UPDATER_PRIVATE_KEY)."
             exit 1
           fi
+      - name: Verify updater signing key matches static pubkey
+        shell: bash
+        env:
+          TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY || secrets.UPDATER_PRIVATE_KEY }}
+          TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD || secrets.UPDATER_PRIVATE_KEY_PASSWORD }}
+        run: |
+          bash scripts/release/verify-updater-keypair.sh
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/release.yml around lines 393 - 396, Add a fail-fast parity
check in the release workflow that, after confirming TAURI_SIGNING_PRIVATE_KEY
is present, derives its public key and compares it to the static updater public
key stored in app/src-tauri/tauri.conf.json; if the derived public key does not
match the configured updater pubkey, exit with a clear error. Locate the check
near the existing TAURI_SIGNING_PRIVATE_KEY presence guard in release.yml, use
the TAURI_SIGNING_PRIVATE_KEY environment variable for derivation, read the
updater public key value from tauri.conf.json, and fail the job when the two
keys differ so installer/update signature mismatches are caught at CI time.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@scripts/prepareTauriConfig.js`:
- Around line 32-35: The signCommand currently interpolates
process.env.KEYPAIR_ALIAS unquoted inside bundle.windows.signCommand which can
break when the alias contains spaces or special chars; update the template in
scripts/prepareTauriConfig.js so signCommand uses a quoted alias (e.g.
--keypair-alias="${process.env.KEYPAIR_ALIAS}") and ensure any embedded quotes
in process.env.KEYPAIR_ALIAS are escaped before interpolation to avoid breaking
the shell command.

---

Outside diff comments:
In @.github/workflows/release.yml:
- Around line 393-396: Add a fail-fast parity check in the release workflow
that, after confirming TAURI_SIGNING_PRIVATE_KEY is present, derives its public
key and compares it to the static updater public key stored in
app/src-tauri/tauri.conf.json; if the derived public key does not match the
configured updater pubkey, exit with a clear error. Locate the check near the
existing TAURI_SIGNING_PRIVATE_KEY presence guard in release.yml, use the
TAURI_SIGNING_PRIVATE_KEY environment variable for derivation, read the updater
public key value from tauri.conf.json, and fail the job when the two keys differ
so installer/update signature mismatches are caught at CI time.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4da36792-3510-4122-8650-6ecf38f9df8b

📥 Commits

Reviewing files that changed from the base of the PR and between 4de34bd and 8025cf4.

📒 Files selected for processing (5)
  • .github/workflows/build-windows.yml
  • .github/workflows/release.yml
  • app/src-tauri/tauri.conf.json
  • scripts/ci-secrets.example.json
  • scripts/prepareTauriConfig.js
💤 Files with no reviewable changes (1)
  • scripts/ci-secrets.example.json

Comment on lines +32 to 35
if (process.env.KEYPAIR_ALIAS) {
bundle.windows = {
signCommand: `smctl.exe sign --keypair-alias=${process.env.KEYPAIR_ALIAS} --input %1`,
};
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Quote KEYPAIR_ALIAS in signCommand to avoid command parsing breakage.

Line [34] interpolates the alias unquoted; aliases with spaces/special characters can break Windows signing command parsing.

Suggested patch
   if (process.env.KEYPAIR_ALIAS) {
+    const escapedAlias = process.env.KEYPAIR_ALIAS.replace(/"/g, '\\"');
     bundle.windows = {
-      signCommand: `smctl.exe sign --keypair-alias=${process.env.KEYPAIR_ALIAS} --input %1`,
+      signCommand: `smctl.exe sign --keypair-alias="${escapedAlias}" --input %1`,
     };
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (process.env.KEYPAIR_ALIAS) {
bundle.windows = {
signCommand: `smctl.exe sign --keypair-alias=${process.env.KEYPAIR_ALIAS} --input %1`,
};
if (process.env.KEYPAIR_ALIAS) {
const escapedAlias = process.env.KEYPAIR_ALIAS.replace(/"/g, '\\"');
bundle.windows = {
signCommand: `smctl.exe sign --keypair-alias="${escapedAlias}" --input %1`,
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@scripts/prepareTauriConfig.js` around lines 32 - 35, The signCommand
currently interpolates process.env.KEYPAIR_ALIAS unquoted inside
bundle.windows.signCommand which can break when the alias contains spaces or
special chars; update the template in scripts/prepareTauriConfig.js so
signCommand uses a quoted alias (e.g.
--keypair-alias="${process.env.KEYPAIR_ALIAS}") and ensure any embedded quotes
in process.env.KEYPAIR_ALIAS are escaped before interpolation to avoid breaking
the shell command.

@senamakel senamakel merged commit b21f64e into tinyhumansai:main Apr 25, 2026
9 checks passed
AusAgentSmith pushed a commit to AusAgentSmith/openhuman that referenced this pull request May 23, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant