fix(tauri): resolve Linux CEF init panic — root/container + SingletonLock + display-server guards (OPENHUMAN-TAURI-K1)#2103
Conversation
…-K1) The SingletonLock check that catches concurrent-launch panics on macOS (issue tinyhumansai#864) was gated to `#[cfg(target_os = "macos")]`. The same panic fires on Linux when a second instance races `cef_initialize` and finds the SingletonLock already held. Extend `cef_preflight`: - `mod cef_preflight` now compiled on `any(macos, linux)` - `check_default_cache` gains a Linux path: honours `OPENHUMAN_CEF_CACHE_PATH` first (always set by `cef_profile::prepare_process_cache_path` before this runs), then falls back to `$XDG_CACHE_HOME/<id>/cef` or `$HOME/.cache/<id>/cef` matching the `dirs::cache_dir()` fallback used by tauri-runtime-cef New tests: - `check_default_cache_uses_configured_env_path` — env-path no-lock - `check_default_cache_env_path_held_returns_err` — env-path held - `check_default_cache_linux_xdg_fallback_no_lock` — Linux XDG fallback
…I-K1) CEF requires a display server (X11 or Wayland) to initialise. On WSL2 without WSLg, and on headless Linux boxes, both DISPLAY and WAYLAND_DISPLAY are unset. In that case `cef_initialize` returns 0 and the vendored `tauri-runtime-cef` assertion fires (`left: 0, right: 1`) — a fatal, silent panic with no actionable error message. Adds `check_linux_display_server()` that runs before the Tauri builder (before `CefRuntime::init`) on Linux only: - If either DISPLAY or WAYLAND_DISPLAY is set → no-op, continue - If both are absent → log an error, print a human-readable message with WSL2 guidance, and exit(1) cleanly Also extends the preflight call site from `#[cfg(macos)]` to `#[cfg(any(macos, linux))]` so the SingletonLock check from commit 021b069 is wired in on Linux too. Mirrors the Windows pre-CEF single-instance guard pattern from tinyhumansai#1723.
…ards
- linux_display_present_with_{x11,wayland,both}: verify pure fn
- linux_display_absent_without_either: no-display → false
cef_preflight tests (check_default_cache_*):
- uses_configured_env_path: OPENHUMAN_CEF_CACHE_PATH no-lock → Ok
- env_path_held_returns_err: env-path with live lock → CefLockError::Held
- linux_xdg_fallback_no_lock (#[cfg(linux)]): XDG_CACHE_HOME redirect,
no lock → Ok
…PENHUMAN-TAURI-K1) Sentry trace shows the panic originates in environments running as root (uid=0) under `/root/.hermes/profiles/coder-bot/home` — CI / coder-bot / Docker containers. The display server was present (Xvfb), so the earlier display-server check does not fire. The issue is Chromium's browser-process root-user check: `cef::initialize` returns 0 unless `--no-sandbox` is passed on the command line. The `no_sandbox: 1` field in `cef::Settings` disables the sub-process sandbox but does NOT satisfy this separate root-user guard. Fix: in `append_platform_cef_gpu_workarounds`, detect `uid == 0` via `nix::unistd::getuid()` (already a dependency) and append `--no-sandbox` to the CEF command-line args. No-op on non-root users and on Windows/macOS (cfg-gated). Also adds the `user` feature to the `nix` dependency (needed for `getuid()`; previously only `signal` was enabled). Tests: - linux_root_uid_detected: uid 0 → true - linux_non_root_uid_not_detected: uid 1000/1 → false
📝 WalkthroughWalkthroughThis PR extends CEF startup safety to Linux: platform-aware cache directory resolution (with env override), display-server presence checks that exit early when missing, root-UID detection that adds ChangesLinux CEF Initialization Safety
Sequence DiagramsequenceDiagram
participant Startup as Startup (run)
participant DisplayCheck as Display Server Check
participant UIDCheck as UID Detection
participant CacheResolution as Cache Resolution
participant CEF as CEF Initialize
Startup->>DisplayCheck: check_linux_display_server()
DisplayCheck->>Startup: DISPLAY or WAYLAND_DISPLAY present?
alt Display server missing
DisplayCheck->>Startup: Exit with error message
Startup-->>CEF: Abort
end
Startup->>UIDCheck: Check process UID
UIDCheck->>UIDCheck: UID == 0?
alt Root detected
UIDCheck->>Startup: Append --no-sandbox to CEF args
end
Startup->>CacheResolution: Resolve cache directory (env or platform default)
CacheResolution->>Startup: Return cache path
Startup->>Startup: Check cache singleton lock
Startup->>CEF: Initialize with flags & cache path
CEF->>CEF: Run
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/src-tauri/src/cef_preflight.rs`:
- Around line 342-419: Tests create per-function local static ENV_LOCKs causing
races; replace them with a single shared module-level lock. Remove the local
`static ENV_LOCK: std::sync::Mutex<()> = ...` declarations in the tests and add
one shared `static ENV_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());`
(or use once_cell::sync::Lazy if needed) at module scope, then keep the existing
lock acquisition lines (`let _guard = ENV_LOCK.lock().unwrap_or_else(|e|
e.into_inner());`) in each test (e.g., check_default_cache_env_path_no_lock,
check_default_cache_env_path_held_returns_err,
check_default_cache_linux_xdg_fallback_no_lock) so all tests serialize access to
process-wide environment mutation.
In `@app/src-tauri/src/lib.rs`:
- Around line 1680-1690: The helper append_platform_cef_gpu_workarounds
currently pushes "--no-sandbox" when running as root using a cfg(target_os =
"linux") block, but that lets the flag be added even when the helper is invoked
with a non-Linux os string; update append_platform_cef_gpu_workarounds to only
append the "--no-sandbox" tuple when the provided os parameter equals "linux"
(e.g., if os == "linux") and then perform the root check (call
linux_is_root_uid()) inside that conditional; reference the function
append_platform_cef_gpu_workarounds, the helper linux_is_root_uid, and the
args.push(("--no-sandbox", None)) site so the flag only gets added for Linux
runs.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: a446aaa6-3a85-4d0c-887a-8bdd281335e6
📒 Files selected for processing (3)
app/src-tauri/Cargo.tomlapp/src-tauri/src/cef_preflight.rsapp/src-tauri/src/lib.rs
… on os param - cef_preflight: replace per-test local static ENV_LOCK with a single module-level static so all env-mutating tests are serialised and cannot race (CodeRabbit suggestion) - lib.rs: add `os == "linux"` guard inside the #[cfg(linux)] block in append_platform_cef_gpu_workarounds so --no-sandbox is only appended when the os param matches, not just the compile-time target (CodeRabbit suggestion)
…Lock + display-server guards (OPENHUMAN-TAURI-K1) (tinyhumansai#2103)
Summary
Problem
Sentry OPENHUMAN-TAURI-K1 reports 55 fatal panics on Linux. The crash is in `CefRuntime::init` where `cef::initialize()` returns 0 and the vendored runtime asserts it equals 1. The Sentry breadcrumbs show the process runs as root under `/root/.hermes/profiles/coder-bot/home` — a CI/container environment. Chromium's browser process silently rejects root unless `--no-sandbox` is on the command line; `Settings.no_sandbox = 1` only disables sub-process sandboxing.
Solution
Windows and macOS are unaffected — all new Linux paths are `#[cfg(target_os = "linux")]`.
Submission Checklist
.github/workflows/coverage.yml. Run `pnpm test:coverage` and `pnpm test:rust` locally; PRs below 80% on changed lines will not merge.Impact
Related
AI Authored PR Metadata (required for Codex/Linear PRs)
Linear Issue
Commit & Branch
Validation Run
Validation Blocked
Behavior Changes
Parity Contract
Duplicate / Superseded PR Handling
Summary by CodeRabbit
Bug Fixes
Tests