ci(release): produce the update feed the app has been polling for - #259
Conversation
Review — approve, no changesConfirmed the premise against the committed config: The gating is the part that makes this safe:
On the manifest generator:
One small thing
|
05a6cd7 to
8dd3b29
Compare
`tauri.conf.json` has carried `updater.active: true`, a committed public key and an endpoint at `releases/latest/download/latest.json` since the desktop app shipped. Nothing ever produced that file. The app polls, 404s, and silently never updates — which is indistinguishable, from the user's side, from an app that is already up to date. The pipeline now closes the loop: `validate` detects the signing key, `build-mac` flips `createUpdaterArtifacts` on and exports the key to `tauri build`, then locates the `.app.tar.gz` and its `.sig`, writes `latest.json`, and `github-release` attaches all three. Every part of it is gated on the key existing. `createUpdaterArtifacts` stays false in the committed config because `tauri build` fails outright when it is true with no key in the environment — leaving it on would break every credential-less release, which is the failure mode RELEASING.md already warned about. And when the key is absent the release body says the feed is missing, for the same reason the DMG and npm skips already say so. The manifest comes from a script with tests, not inline YAML. Its shape is a contract with the updater, and a wrong field name fails the way a missing file does: quietly, in the user's app, long after the release was cut. It refuses to emit an empty signature — the plausible mistake is globbing up a `.sig` that was never written — and pins the download URL at the tag rather than `/latest/`, so a manifest a client already fetched keeps resolving to the build its signature was made for. Not verifiable here: this needs a signing key and a macOS runner. The YAML parses, the step ordering is asserted, and the manifest builder is unit-tested; the build steps themselves are first exercised by the next tagged release. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The app has been asking for a file nobody makes
tauri.conf.jsonhas carried this since the desktop app shipped:Nothing ever produced
latest.json. So the app polls, gets a 404, and silently never updates — which from the user's side is indistinguishable from an app that is already current.Change
TAURI_SIGNING_PRIVATE_KEY→has_updatervalidatebundle.createUpdaterArtifactsonbuild-mac, before the buildtauri buildbuild-mac*.app.tar.gz+.sig, writelatest.jsonbuild-mac, after signinggithub-releaseEverything is gated on the key existing.
createUpdaterArtifactsstaysfalsein the committed config becausetauri buildfails outright when it is true with no key in the environment — leaving it on would break every credential-less release, which is precisely the trapRELEASING.mdalready warned about. CI flips it, and only when the key is there.When the key is absent, the release body says so — same treatment the missing DMG and missing npm publish already get. An updater polling a 404 forever looks exactly like one that found no update, so silence is the wrong default.
The manifest is a script with tests, not inline YAML
Its shape is a contract with the updater, and a wrong field name fails the way a missing file does: quietly, in the user's app, long after the release was cut.
.sigthat was never written because the key was missing — that manifest is rejected by every client, so failing the release is better than publishing an update nobody can install./latest/. A client that already fetched the manifest must keep resolving to the build its signature was made for.Verification, honestly
This needs a signing key and a macOS runner, so I could not execute the build steps. What I did verify:
Enable updater artifactsbefore the build,Stage updater bundle + manifestafter;The build steps themselves are first exercised by the next tagged release. That is a real limit, and it is the same class of thing that produced the five consecutive v0.3.0 release failures — which is why every new step fails loudly with a diagnostic rather than proceeding on a guess.
Still yours
Generate the key pair and add two secrets:
pnpm --filter @deepcode/desktop exec tauri signer generate -w deepcode-updater.key🤖 Generated with Claude Code