Desktop: ship a complete Linux AppImage - #9113
Conversation
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 59d45f24c0
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| APPDIR=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd -P) | ||
| PATH="$APPDIR/usr/bin:$APPDIR/usr/sbin:${PATH:-/usr/local/bin:/usr/bin:/bin}" | ||
| export APPDIR PATH |
There was a problem hiding this comment.
Clear inherited library overrides before launching the AppImage
When the AppImage is started from an activated Conda/venv or any shell with LD_LIBRARY_PATH set, this launcher preserves that value. The dynamic loader searches LD_LIBRARY_PATH before the newly assigned DT_RUNPATHs, so host copies of GLib, GTK, WebKit, or GStreamer can override the bundled runtime and recreate the mixed-library crashes this complete AppImage is intended to prevent. Remove or sanitize inherited library paths before executing the desktop binary while continuing to leave graphics/driver libraries available through the normal system lookup.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 4087cbe. The AppRun now moves an inherited LD_LIBRARY_PATH into UNSLOTH_HOST_LD_LIBRARY_PATH and unsets it before exec'ing the bundled binary, so the $ORIGIN RUNPATHs the finalizer sets are what resolve GLib, GTK, WebKit and GStreamer.
Managed children keep the old behaviour: scrub_appimage_library_path in process.rs falls back to the saved value, so host CUDA and ROCm directories still reach the backend and host launchers, and graphics and driver libraries still resolve through ld.so.cache and the default directories.
verify-complete-appimage.sh now rejects a launcher that keeps the inherited value, and tests/security/test_release_desktop_appimage.py runs the real AppRun with LD_LIBRARY_PATH set and asserts the bundled binary does not receive it. That test fails against the previous launcher.
|
@codex review |
|
Codex Review: Didn't find any major issues. 🎉 Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Going to test out later today! Sorry for the wait. I am concerned about merging that LD_LIBRARY_PATH change, that could easily cause problems on immutable systems. |
|
@ThomasEricB what kind of problems? Can you generate a reproducible one? |
|
Sometimes LD_LIBRARY_PATH can be way too finicky on my linux experience. I would have to test to see if everything is airtight as it seems. |
|
Confirmed the thin path in studio/src-tauri/linux/build-thin-appimage.sh still requires host WebKitGTK 4.1, GTK and AppIndicator, which is exactly what breaks startup on Fedora and immutable distros. The branch is conflicting with main right now, so please rebase and I will get this reviewed. |
|
@codex review |
|
Codex Review: Didn't find any major issues. Breezy! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
Give me 30 minutes I will turn on my steam deck. I will not keep you waiting sorry @oobabooga |
|
@ThomasEricB if you encounter any issues let me know and I'll address in a follow-up. |
|
Ok apologies something came up. I'll try to test it soon. |
…giene (#9370) `Desktop app clean machine` is red nightly on main, seven AppImage jobs, all with the app's own preflight naming four missing sonames. The tree is not at fault and neither is the test, so this changes only what the verifier says. What is actually happening ------------------------------------------------------------------------ The scheduled run downloads the published release rather than building one. `REL_TAG` is `v0.1.800-beta`, whose Linux asset was uploaded 2026-08-14T15:26Z and never rebuilt. I extracted it: `usr/bin/unsloth-studio` and zero `.so` files, so it resolves webkit2gtk, libsoup, javascriptcoregtk and appindicator from the host. It is a pre-#9113 thin build, provably: the diagnostic it prints lives at line 210 of `build-thin-appimage.sh`, a script #9113 deleted, and the replacement `appimage-apprun.sh` does not contain that string. #9113 ("Desktop: ship a complete Linux AppImage") landed 2026-08-19T13:09Z and also dropped the line that used to install the host runtime into the appimage row, which is correct under a self-contained bundle and is why that row flipped on an unchanged asset. The Aug 18 run was green, Aug 19's red was the ManagedStale incident that #9263 fixed, and Aug 20 is the first scheduled run after #9113. So the asset under test predates the packaging it is being tested against. The first desktop release cut from current main will satisfy these jobs; nothing in the tree needs changing to make that true, and until that release exists this workflow is red for a correct reason. Note this is invisible on a pull request by construction: on `pull_request` the AppImage jobs consume the artifact from `appimage-pr-build`, built from the PR, so #9113 was green when it merged. Only `schedule` and `push` reach the release. The one real defect ------------------------------------------------------------------------ `verify-complete-appimage.sh` run against that asset reports: Complete AppImage does not clear an inherited LD_LIBRARY_PATH It exits 1 correctly, but it fails at the launcher-hygiene check and never reaches the required-component loop, so a bundle that ships NO runtime at all is reported as an environment-variable bug. That is the difference between an hour of diagnosis and a minute of it. The required-component check now runs first and reports every miss instead of exiting on the first, mirroring the AppRun preflight, which names all four sonames at once rather than making the reader rediscover them one launch at a time. On the published asset it now says: Complete AppImage is missing required runtime component: libwebkit2gtk-4.1.so* ... 21 lines ... Complete AppImage is missing 21 of 21 required runtime components; it resolves them from the host Order only. No check is removed and no assertion is weakened. Verified ------------------------------------------------------------------------ `bash -n` clean. A synthetic AppDir with all 21 components present falls through to the launcher-hygiene check exactly as before, so the hygiene checks still run and still fail when they should. Removing only webkit from that AppDir yields `missing 1 of 21`, so the count is real rather than a formatting flourish. tests/security/test_release_desktop_appimage.py: 15 passed.
Re-lands #8695, reverted in #8823, together with #8813 and the remaining fixes needed for a complete AppImage. #8695 is @wasimysaid's work; #8813 ports the two runtime fixes @ThomasEricB identified and tested in #8343.
Why
The AppImage has been thin since #7953. That avoided mixing an Ubuntu 22.04 web runtime with newer host libraries, which caused failures such as:
The thin bundle instead requires the host to provide GTK, WebKitGTK 4.1, JavaScriptCore and AppIndicator. This does not work on distributions such as Fedora 44 KDE or immutable systems where those packages are unavailable or cannot be installed.
This PR restores a complete AppImage while preserving the #7953 boundary: the bundle owns one coherent Ubuntu 22.04 userspace web runtime, while libraries coupled to host services, display servers and drivers remain host-owned.
What changed
linuxdeploytool and plugin by digest.LD_LIBRARY_PATH. Bundled ELF objects use$ORIGINRUNPATHs instead.GTK_PATH,GIO_MODULE_DIRand the GStreamer plugin paths to the bundle. Remove foreign-architecture GIO modules copied from multilib build hosts.libvaandlibvdpausolibgstlibavalso loads on hosts without VA-API.linuxdeploydoes not guarantee plugin order.$APPDIR/usras an invalid working directory for managed children and fall back to~/.unsloth. Scrub bundle-only GUI and Python variables before launching managed processes, browsers or file managers..DirIconso it is relative rather than a build-machine symlink.The finished-artifact verifier now checks every ELF object, not only the main executable. It rejects foreign architectures, absolute or non-
$ORIGINRUNPATHs, forbidden host libraries, unpinned module paths, missing media plugins, and invalid desktop links.LC_ALL=Cmakes itsreadelfchecks independent of the builder locale.Verification
All results below use one AppImage built in
ubuntu:22.04with the release workflow's pinned toolchain:Startup and desktop authentication passed without host GTK, WebKitGTK, JavaScriptCore or AppIndicator:
libGLESv2.so.2The Mint run used the live session that reproduced #7953, including its
GTK_MODULESandGTK3_MODULES. The bundled GTK declined the host modules and started without loader errors. The managed backend ran from~/.unsloth, not the read-only AppImage mount.The packaged WebKitGTK model-download flow passed on Ubuntu 22.04, Ubuntu 24.04 and Mint 22:
Every portability lane also loaded the bundled GStreamer registry and decoded real H.264 frames:
The artifact contains 581 x86-64 dynamic ELF objects. None has a RUNPATH outside
$ORIGIN, an absoluteDT_NEEDED, or a baked-in builder path. The bundle ships nolibnghttp2,libcurlorlibstdc++, and no launcher or hook exports a globalLD_LIBRARY_PATH.For comparison, a rebuilt pre-#7953 complete AppImage failed on Mint by loading host gvfs modules into bundled GLib, failed on Fedora with
EGL_BAD_PARAMETER, and shipped a dangling absolute.DirIcon. The new artifact passes those same lanes and checks.Test suites:
cargo test --no-fail-fastinstudio/src-tauri: 378 passedruff checkand the repository format hook on changed Python filesbash -non the packaging scripts andgit diff --checkBoundaries and limits
libstdc++,libgcc_s,libnghttp2andlibcurl.gstreamer1.0-libavand its dependency closure.GDummyProxyResolverrather than the host'sGLibproxyResolver, so Hugging Face README, avatar and dataset panels ignore a desktop proxy. Model downloads run in the backend and updates in the Rust HTTP client, so both still honour the proxy environment. This arrived with Desktop: ship a complete Linux AppImage #8695's pin, which is what stops host GIO modules loading into the bundled GLib.