feat(updates): harden in-place update safety and recovery - #506
spandan11106 wants to merge 7 commits into
Conversation
Name the release an install is for rather than pointing at a URL: the installer derives the download location from the tag and asset name and refuses a release feed that advertises anything else. Cap both the archive and the published checksum against advertised and streamed byte counts. Replace the tar subprocess with in-process extraction that rejects symlinks, hard links, devices, absolute paths and parent-directory escapes before anything reaches the filesystem, and bounds entry count and extracted size. Authenticate the archive with its GitHub build-provenance attestation and match its SOURCE_COMMIT against the commit the release tag resolves to, failing closed on either. A checksum published beside the archive proves only that the two agree. Preserve the previous executable across a replacement, restore it if the new one does not run, and let the restart waiter put it back when the replacement fails to start. Installs can now be cancelled from both the settings row and the update dialog.
|
Merged current
Manual verification: authenticated the published Visual evidence: N/A for these review fixes; no interface layout, styling, or controls were changed. I did not exercise a complete live GUI self-update or capture cancellation media. |
|
Guided testing exposed a verification hang: gh probes Secret Service even with an empty configuration, and an isolated/locked desktop keyring can stall that lookup. Fixed in a93e746: the verifier now uses disposable CLI configuration, removes token environment variables, disables prompting, and prevents Secret Service access for this public-release operation. No account or token is required, and signature/repository/workflow checks remain enforced. Confirmed in a fresh private D-Bus session without credentials: the published v0.11.2 archive verified in 3.9 seconds; the wrong signer workflow failed. Added regression coverage for the subprocess environment. The rebuilt guided fixture is staged for another user testing pass. No visual controls/layout changed. |
|
Guided user verification completed successfully after a93e746: Settings cancellation left the executable unchanged; the sidebar install completed through anonymous provenance verification; Restart now reopened the disposable installation with TEST-FIXTURE.txt still visible; a subsequent update check reported up to date. The target was the real published v0.11.2 release. Sidebar cancellation was not separately completed, and the target predates rollback-cleanup support, so those remain unverified manually. |
|
Updated from main (c74e33a), resolving the settings conflict by retaining the new preference bindings and the structured install request. Replaced the CLI verifier in a430d39 with native Ed25519 signed-manifest authentication and in-process SHA-256 verification; no gh, account, token, or keyring is involved in update authentication. The separate signing job runs trusted workflow-revision tools, uses the approval-protected/main-only release-signing environment, and must succeed before publication. The production public key is embedded, the private key is provisioned as an environment secret, and dual-signature rotation plus compromise/rollout procedures are documented in docs/signed-updates.md. No release was dispatched or existing release modified. Verified OpenSSL/Rust interoperability with non-production keys and exercised valid/tampered signed archives through verification, extraction, staging, and executable replacement. Also ran all 11 native manifest/pipeline tests with PATH=/nonexistent, an empty home, no credentials, and no desktop bus; all passed. The first real signed-release workflow run remains a post-merge maintainer step; existing unsigned releases deliberately fail closed. This replaces the previous gh-based guided-testing path, not merely its credential configuration. |
Merge BlockerRelease packager and extractor still disagree on GNU tar LongLink. Reproduced: stable Required before land: pack with |
|
Merged current main (1ea889e) into this PR with merge commit b9b2b61, without conflicts or rebasing. The signed-manifest updater remains intact; no additional code fixes were needed. Full local checks passed, including isolated GTK tests and the canonical rootless-Podman GUI suite. No visual changes beyond those already on main. |
Description
Hardens in-place updates for #148 and replaces the GitHub CLI verifier with native signed-manifest verification.
gh, account, token, keyring, or external verification tool.Rollout: existing unsigned releases are refused with a manual-install fallback. The first signed release must be published after this workflow lands; there is no checksum-only or
ghfallback. GitHub attestations and checksum assets remain available for independent verification and packaging. Trust format, key operations, rotation, and limitations are documented indocs/signed-updates.md.Visual evidence
N/A for the signed-manifest revision: authentication/release infrastructure changed, not interface layout or controls. The existing cancellation controls were exercised during guided testing; no media was captured. The earlier successful live update used the previous verifier, not this new protocol.
How to test
ghor credentials. In Settings → Updates, install that release and cancel; confirm the existing executable is unchanged and installation can be retried.release-signingenvironment only after reviewing the selected source/version, then approve publication. Confirm both manifest files accompany the architecture archives. The signing key must matchdata/update-keys.json.Expected result: public updates authenticate natively before extraction or execution, invalid/unsigned updates fail closed, cancellation preserves the working install, and successful replacement restarts normally. A target predating this PR cannot perform the new rollback-cleanup callback.
Related issue
Closes #148