Skip to content

fix(desktop): keep durable CLI symlink when the bundle is ephemeral - #6185

Open
santhiprakash wants to merge 1 commit into
block:mainfrom
santhiprakash:fix/desktop-cli-symlink-ephemeral-appimage
Open

fix(desktop): keep durable CLI symlink when the bundle is ephemeral#6185
santhiprakash wants to merge 1 commit into
block:mainfrom
santhiprakash:fix/desktop-cli-symlink-ephemeral-appimage

Conversation

@santhiprakash

Copy link
Copy Markdown

Summary

ensure_cli_symlink removes and recreates ~/.local/bin/buzz on every boot from current_exe().parent() (lib.rs setup). A Linux AppImage runs from an extract under the temp dir, so the link is rewritten to /tmp/appimage_extracted_*/usr/bin/buzz (or /tmp/.mount_*/…). /tmp is tmpfs on many distros, so after the next reboot the target is gone: buzz is still on PATH, still dangles, and desktop reports nothing — agents and timers just stop posting.

Refreshing the link unconditionally is deliberate (#1357 — the older code only updated targets containing .app/Contents/MacOS, so Linux links kept naming a moved bundle). This keeps that and carves out only the case that makes it lossy:

  • This boot's bundled CLI is durable → replace the link exactly as today.
  • This boot's bundled CLI is ephemeral (under the process temp dir or literal /tmp, so TMPDIR pointing elsewhere still can't hide a /tmp extract) and the existing link resolves to a durable binary → leave the link alone.
  • Ephemeral bundle, but the link is missing / dangling / unreadable / itself under an ephemeral root → still write it, so an AppImage-only machine keeps the convenience link and a stale extract path still gets refreshed.

Regular files at the link path are still skipped, unchanged.

Deliberately out of scope: an AppImage-only machine with no durable CLI still ends up with a link into the extract, which still dangles after reboot. Making that durable means copying or hardlinking the sidecar out of the extract — a bigger behavior change than this bug needs, and worth its own issue.

The link directory and the ephemeral roots are now parameters of an inner ensure_cli_symlink_in, so the new tests drive the real remove_file/symlink writes against a temp tree instead of restating the branch logic (the pre-existing tests could not call the function at all, because the link directory came straight from dirs::home_dir()).

Related issue

Fixes #6110

Duplicate search: none found. ensure_cli_symlink in PR search returns only merged #1357 and #1587; no open PR references #6110. Closest open issue is #3471 (the installer GUI wrapper named buzz), a different failure that the reporter also called out.

Testing

  • cargo test --manifest-path desktop/src-tauri/Cargo.toml --lib nest::46 passed, 0 failed (2490 filtered out), including the 8 new cases:
    • ensure_cli_symlink_keeps_durable_link_when_bundle_is_ephemeral — the reported bug: on current main the is_symlink branch removes and recreates the link unconditionally, so it ends up naming the extract.
    • ensure_cli_symlink_refreshes_link_when_bundle_is_durable — guards fix: unconditionally replace CLI symlink on boot #1357's behavior.
    • ensure_cli_symlink_creates_link_for_ephemeral_bundle_when_absent
    • ensure_cli_symlink_leaves_regular_file_alone_for_ephemeral_bundle
    • keeps_durable_relative_cli_symlink_when_bundled_cli_is_ephemeral — relative link targets resolve against the link's own directory.
    • retargets_dangling_cli_symlink_when_bundled_cli_is_ephemeral
    • retargets_stale_ephemeral_cli_symlink_when_bundled_cli_is_ephemeral
    • ephemeral_exe_roots_always_include_tmp_and_process_temp_dir
  • rustfmt --check clean on both touched files.
  • Host is Linux (aarch64). The ephemeral roots are injected as data in tests rather than patching the host's temp dir, so the same assertions hold on macOS, where an app bundle in /Applications is durable and takes the unchanged path.
  • Screenshots: N/A (no UI change).

`ensure_cli_symlink` removes and recreates `~/.local/bin/buzz` on every
boot from `current_exe().parent()`. A Linux AppImage runs from an extract
under the temp dir, so the link gets rewritten to
`/tmp/appimage_extracted_*/usr/bin/buzz` (or `/tmp/.mount_*/...`). `/tmp`
is tmpfs on many distros, so after the next reboot the target is gone and
anything invoking `buzz` by name fails with nothing surfaced by desktop —
agents and timers just stop posting.

Refreshing the link unconditionally was deliberate (block#1357): the older
code only updated targets containing `.app/Contents/MacOS`, so Linux
links kept naming a moved bundle. Keep that, and carve out only the case
that makes it lossy — when this boot's bundled CLI is itself ephemeral
and the existing link still resolves to a durable binary, leave the link
alone. A missing, dangling, unreadable, or itself-ephemeral target is
still replaced, so an AppImage-only machine still gets the convenience
link and a stale extract path still gets refreshed.

The link directory and the ephemeral roots are now parameters of an inner
`ensure_cli_symlink_in`, so the tests drive the real filesystem writes
instead of restating the branch logic.

Fixes block#6110

Signed-off-by: Santhi Prakash <b.santhiprakash@gmail.com>
@santhiprakash
santhiprakash requested a review from a team as a code owner August 18, 2026 01:19
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.

Desktop: ensure_cli_symlink retargets ~/.local/bin/buzz at the AppImage extract under /tmp

1 participant