Repository navigation
feat: add dormant Sparkle auto-update integration (PR A) - #127
Merged
Merged
Conversation
Link, embed, sign and verify Sparkle 2.10.0 in every build while shipping no update feed. The SU* keys exist only in a plist passed to build-app.sh --updates --update-info, which refuses ad-hoc signing, so dev, PR and release-pipeline builds stay inert: the configuration gate resolves to unavailable, no driver is created, nothing contacts a server and the update UI is hidden. - UtterUpdates module (portable gate, status reducer, busy-held relaunch; Sparkle only under Native/), UpdateService contract and presentation - automaticUpdateChecks setting (default on), en and zh-Hans strings - embed-sparkle.sh, verify-sparkle.sh, update-options.sh, check-update-plist.py; three-pass signing with Sparkle components signed without entitlements - verify-release-artifact.sh checks Sparkle layout and signing on every build and forbids SU* keys unless --require-updater - SDLC bundle with intent, spec, plan and approved Part A verification Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Outcome
PR A of two for in-app auto-update (Sparkle 2.10.0, pinned exact): the dormant integration. Sparkle is linked, embedded, signed and verified in every build, and the code that drives it exists, but no build carries an update feed. The
SU*keys exist only in a plist passed tobuild-app.sh --updates --update-info, which refuses ad-hoc signing, and none is committed. Dev, PR, manual and release-pipeline builds therefore stay inert: the configuration gate resolves tounavailable, no driver is created, nothing contacts a server, and the update UI is hidden. PR B (separate) adds the committed key plist, the release-pipeline metadata steps, docs and the rehearsal.Originating decision: intent, spec and plan are approved in the bundle below.
SDLC bundle and risk
docs/sdlc/changes/2026-10-17-auto-update/(intent, spec, plan approved;verification.mdapproved for Part A on 2026-10-17)What changed
UtterUpdatesmodule: portable configuration gate, status reducer, busy-held relaunch gate and controller; Sparkle only underNative/.UpdateServicecontract,UpdateProjection, menu row and About section (hidden when inert),automaticUpdateCheckssetting (default on),enandzh-Hansstrings. The updater is excluded from the recovery composition.embed-sparkle.sh(embed, dropXPCServices, thin to arm64, add rpath), three-pass signing with the Sparkle components signed inside-out with the hardened runtime and no entitlements,update-options.sh,check-update-plist.py.verify-release-artifact.sh: Sparkle layout and signing are checked on every build (hardened runtime, same signer as the app, no entitlements, timestamp for Developer ID);SU*keys are forbidden unless--require-updater..github/workflows/**,Resources/Info.plist,Resources/OpenType.entitlements; no ATS exception;Package.resolveddiffers only by the Sparkle pin andoriginHash.Verification
Evidence:
verification.mdandevidence/.bash scripts/sdlc-checks.sh(the template'spython3 scripts/sdlc.py validate --worktreedoes not exist in this repo)bash scripts/ci-basic-checks.sh(script tests 31 → 52)swift test(XCTest 1143 → 1193, 0 failures, same 18 skips)--updates, and the PR-CI style--sign=-); nested signatures and entitlements equal the v0.0.55 baseline apart from the new rpath--require-updater) is fixed and re-checked as resolvedResidual risk and rollback
SPUUpdaterpath is compiled and driven by fakes only; it cannot run in a shipped build until PR B, whose rehearsal is the first end-to-end proof.Reviewer focus
scripts/verify-sparkle.shand the three-pass signing inscripts/build-app.sh: any way a check can pass vacuously, or Sparkle's installer can inherit the app's entitlements.UpdateConfiguration.resolve,check-update-plist.py --forbid,--updatesrefusing ad-hoc).ModelCatalogSnapshot.isBusy, which does not exist; the implementation usesCatalogModelStatus.isBusyover all catalogs (documented inverification.md, spec not edited).