fix(claude_desktop): address review nitpicks on PR #2893

- 21-gpu_permissions.sh: distinguish the expected getent exit 2
  (unnamed GID) from other getent failures, warning instead of
  silently masking unrelated NSS/database errors.
- SIGN_IN.md: state explicitly that --password-store=basic trades
  away OS-backed at-rest protection.

Addresses CodeRabbit nitpicks from the PR review. The symlink-following
concern on 85-openbox_autostart.sh raised by CodeRabbit and Codex is left
open for maintainer review (see PR comment).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
alexbelgium
2026-07-23 08:35:13 +02:00
parent f0097ad467
commit ea46cbf8a5
3 changed files with 13 additions and 3 deletions

View File

@@ -4,7 +4,8 @@
- Fix recurring "For your security, sign in again to keep using Claude." and the Claude app's dispatch tab showing this desktop as offline when opened from mobile first. Root cause (confirmed from `~/.config/Claude/logs/main.log` on a live install): the app launches with `--password-store=gnome-libsecret`, forcing Electron's libsecret/Secret-Service backend, but `gnome-keyring` was removed from the image in a previous commit because it prompted for a keyring password on first boot and blocked the app from launching. With the flag still forcing libsecret and no keyring daemon running, `safeStorage.isEncryptionAvailable()` is `false` — logs showed `session will not persist; app secrets fall back to plaintext` and `cannot store allowlist cache`. The un-persisted session then goes stale, failing the elevated-access OAuth check (`session_stale_relogin`) that the cowork/dispatch bridge needs, so the bridge is "parked until re-login" — which is what the Claude app surfaces as the desktop being offline, until a fresh sign-in (only completable from a computer, see `SIGN_IN.md` Problem A) un-parks it. `rootfs/defaults/autostart` now launches with `--password-store=basic` instead: Electron's built-in fixed-key store needs no daemon and never prompts, and persists under `$HOME/.config/Claude` (`/data/data`, persistent), so the session survives restarts and dispatch stays online regardless of which device connects first. A passwordless keyring was considered and rejected — it would live in the same persistent volume as the ciphertext, adding no real protection in this single-user self-hosted setup. `Dockerfile`'s stale comment (still describing gnome-keyring as installed) is corrected; the package stays removed.
- New `85-openbox_autostart.sh`: the app is actually launched from the *persistent* `$HOME/.config/openbox/autostart`, which the base image's `init-selkies-config` oneshot only seeds from `/defaults/autostart` when the persistent copy is missing — so on any existing install, editing `/defaults/autostart` alone would never reach the file actually being run. This new cont-init script re-syncs the persistent copy from the image on every boot (as root, before any s6-rc service starts, so it also overwrites a copy a prior boot may have left root-owned/read-only under `RESTART_APP`), so the `--password-store` change (and any future autostart change) reaches existing installs on upgrade, not just fresh ones.
- One-time step after upgrading: the previously-stored session is already stale, so complete one sign-in from a computer (mobile cannot complete the OAuth flow in the streamed desktop, see `SIGN_IN.md` Problem A). The session then persists normally.
- Fix `21-gpu_permissions.sh` failing at boot (`exiting 2`) while working fine when re-run manually. Root cause: the script runs under bashio, which sets `set -o pipefail`, together with the script's own `set -e`; `getent group "$gid" | awk ...` exits 2 whenever `$gid` has no named group yet, which is the normal case here because this script deliberately runs *before* the base image's `init-video`/`init-adduser` have named the passed-through `/dev/dri` gids. That exit 2 aborted the script immediately, before reaching its own `-z "$gname"` fallback (written specifically to create a `dri<gid>` group for exactly this unnamed case) — and, as a side effect, before the `chmod o+rw` fallback further down, so the boot-time GPU-permission hardening from 1.31 wasn't fully applied either. A manual re-run afterward always "worked" because by then `init-video` had already named the group. Fixed by not letting that expected exit propagate: `gname="$(getent group "$gid" | awk -F: '{print $1}')" || gname=""`.
- Fix `21-gpu_permissions.sh` failing at boot (`exiting 2`) while working fine when re-run manually. Root cause: the script runs under bashio, which sets `set -o pipefail`, together with the script's own `set -e`; `getent group "$gid" | awk ...` exits 2 whenever `$gid` has no named group yet, which is the normal case here because this script deliberately runs *before* the base image's `init-video`/`init-adduser` have named the passed-through `/dev/dri` gids. That exit 2 aborted the script immediately, before reaching its own `-z "$gname"` fallback (written specifically to create a `dri<gid>` group for exactly this unnamed case) — and, as a side effect, before the `chmod o+rw` fallback further down, so the boot-time GPU-permission hardening from 1.31 wasn't fully applied either. A manual re-run afterward always "worked" because by then `init-video` had already named the group. Fixed by not letting that expected exit propagate: `gname="$(getent group "$gid" | awk -F: '{print $1}')" || gname=""`. The fallback now also distinguishes the expected exit 2 (unnamed GID) from any other `getent` failure, logging a warning instead of silently treating unrelated NSS/database errors the same way.
- `SIGN_IN.md` now states explicitly that the `basic` password store trades away OS-backed at-rest protection for the persisted session.
## 1.34 (22-07-2026)

View File

@@ -107,7 +107,9 @@ entirely.
`--password-store=basic` instead of `gnome-libsecret`. `basic` is Electron's built-in
fixed-key store: `isEncryptionAvailable()` is always `true`, no daemon, no prompt. Secrets
land under `$HOME/.config/Claude`, and `HOME=/data/data` is persistent add-on storage, so
the session survives restarts.
the session survives restarts. `basic` trades away OS-backed at-rest protection: unlike
`gnome-libsecret`, its encryption key isn't gated by a keyring daemon, so any process able
to read the persistent `$HOME/.config/Claude` profile can recover the saved credentials.
2. A passwordless keyring was considered instead (keeps libsecret encryption-at-rest without
a prompt) and rejected: the keyring DB would live in the same persistent volume as the
ciphertext it's "protecting," so it adds ~no real confidentiality in this single-user

View File

@@ -42,7 +42,14 @@ for node in "${dri_nodes[@]}"; do
# bashio manually re-running this script post-boot always "worked": by then the base
# image's own init-video oneshot had already named the group, so getent no longer hit its
# exit-2 path.
gname="$(getent group "$gid" | awk -F: '{print $1}')" || gname=""
if gname="$(getent group "$gid" | awk -F: '{print $1}')"; then
rc=0
else
rc=$?
if [ "$rc" -ne 2 ]; then
bashio::log.warning "getent group ${gid} failed unexpectedly (exit ${rc}); falling back to a synthetic group"
fi
fi
if [ -z "$gname" ]; then
gname="dri${gid}"
groupadd -o -g "$gid" "$gname" 2> /dev/null || true