Skip to content

feat: crash-safe process-external Linux AppImage handoff - #291

Merged
turinglambdaai merged 2 commits into
mainfrom
feature/appimage-update-handoff
Oct 19, 2026
Merged

turinglambdaai merged 2 commits into
mainfrom
feature/appimage-update-handoff

Conversation

@turinglambdaai

Copy link
Copy Markdown
Owner

Closes #290.

What

Adds AppImageHandoff to the linked rivet::platform target — the Linux counterpart of the Windows MsiHandoff. A GTK host applying an AppImage update must not run the swap itself: a crash between moving the old AppImage aside and moving the new one into place leaves no executable at the launch path, and the dead process could never run recovery. Instead, LaunchReplacement writes a generated first-party shell script into a process-specific attempt directory and detaches it, so the updating process can exit right after releasing its single-instance lease.

Lifecycle (mirrors the issue's requested API)

  1. Accepts the already authenticated/verified candidate (download-update + verify-update-artifact! output); the script re-checks size-independent SHA-256 before anything moves.
  2. The helper is detached before the caller's release_lease callback runs.
  3. It waits a bounded time (exit_timeout_seconds) for the launching process to exit; a miss records process-exit-timeout.
  4. Out of process it performs the same atomic replace as execute-platform-installation!: staging copy beside the target, renamed swap, schema-1 journal phases, idempotent rollback gated by the signed manifest's rollback policy. Concurrency is serialized by a self-healing lock (stale owner PID is reaped).
  5. It relaunches the replacement and health-gates on a settle window.
  6. Commit only after the replacement survives; otherwise restore the previous AppImage (unless rollback is forbidden) and record failure.txt.
  7. ConsumeFailure / CleanupStaleAttempts complete the startup lifecycle, mirroring Windows.
  8. deb/rpm stay owned by the system package manager — this API is only for AppImage targets.

The journal lives at the deterministic sibling path <target>.rivet-handoff-journal with the same fields and phases as the runtime transaction, so an interrupted handoff stays recoverable with recover-platform-installation!. A preflight heals attempts that died between the two renames, so the launch path is never left without an executable.

Validation

  • platform/linux/Integration/update_handoff_test.cpp now drives the real detached helper end to end on Linux CI: healthy commit, unhealthy rollback, rollback-forbidden, digest mismatch, and exit-timeout scenarios (wired into the Linux roundtrip job).
  • rivet/tests/linux-update-handoff.rkt pins the generated lifecycle semantics on every host, in the same style as the Windows handoff guard; raco test rivet/tests/ passes locally (10119 tests).

AppImageHosts that exit to apply an update cannot run the swap themselves:
a crash between moving the old AppImage aside and moving the new one into
place leaves no executable at the launch path, and the dead process could
never run recovery. AppImageHandoff::LaunchReplacement (the Linux
counterpart of MsiHandoff) writes a generated first-party shell script,
detaches it, and lets the updating process exit after releasing its
single-instance lease. The script waits a bounded time for the launching
process, serializes concurrent helpers through a self-healing lock,
performs the atomic replace with staging, SHA-256 re-check, schema-1
journal phases, and idempotent rollback, relaunches the replacement, and
commits only after it survives the settle window. Failures record a
failure marker for ConsumeFailure/CleanupStaleAttempts on the next
launch, and a preflight heals attempts that died between the two renames.
Closes #290.
journal_writer takes the pre-rendered journal record, waitpid and chmod
need their headers, and the detached helper does not need a working
directory change since every path it sees is absolute.
@turinglambdaai
turinglambdaai merged commit 761a6ba into main Oct 19, 2026
23 checks passed
@turinglambdaai
turinglambdaai deleted the feature/appimage-update-handoff branch October 19, 2026 17:55
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.

Updater: add crash-safe external handoff for Linux AppImage replacement

1 participant