mirror of
https://github.com/alexbelgium/hassio-addons.git
synced 2026-10-30 17:41:44 +00:00
Compare commits
14
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8d11bfe8e1 | ||
|
|
587121cb1b | ||
|
|
29f2cfd198 | ||
|
|
3329c4b40d | ||
|
|
9471dffcca | ||
|
|
215327e439 | ||
|
|
8ecbfccdcd | ||
|
|
5a2efc4f9e | ||
|
|
ef0aecbde6 | ||
|
|
7a6ad72617 | ||
|
|
b5985f230e | ||
|
|
d48d1f4d8d | ||
|
|
6bf379bffc | ||
|
|
5d577ad954 |
No files matched your search
@@ -1,3 +1,15 @@
|
||||
## 1.23 (15-07-2026)
|
||||
|
||||
- Expose `SUDO_PASSWORD`, per LinuxServer.io's base-image convention: setting it grants the `abc` user sudo access gated by that password. Sudo access stays disabled by default when left unset. Passed straight through by the existing option-to-env-var mechanism; no rootfs changes needed.
|
||||
|
||||
## 1.21 (15-07-2026)
|
||||
|
||||
- Fix Claude Code bypass permissions being rejected when the add-on uses its default root `PUID`.
|
||||
- In `permission_mode: bypass`, remap the shared `abc` Desktop runtime to an unused non-root UID before storage ownership and Selkies startup, while retaining its configured primary group for mounted-path access.
|
||||
- Make folder setup and final Claude configuration ownership follow the effective `abc` identity instead of the configured root UID.
|
||||
- Drop root console invocations of the add-on's `/usr/local/bin/claude` wrapper to the non-root `abc` runtime before passing `--dangerously-skip-permissions`.
|
||||
- Extend `claude-tools-doctor.sh` with configured/effective UID and GID checks for bypass mode.
|
||||
|
||||
## 1.20 (15-07-2026)
|
||||
|
||||
- Complete the TokenSave Claude Code integration at startup: install its MCP server, permissions, PreToolUse/UserPromptSubmit/Stop hooks, global guidance, and Git synchronization hooks instead of registering only `tokensave serve`.
|
||||
|
||||
@@ -35,6 +35,10 @@ PATH tools.
|
||||
`/usr/bin/claude` directly, the session remains functional and still has the
|
||||
shared permission mode and Headroom MCP tools, but transparent proxy
|
||||
compression cannot be injected.
|
||||
- When `permission_mode: bypass` is selected while `PUID` is `0`, the add-on
|
||||
automatically remaps the shared `abc` desktop account to an unused non-root
|
||||
UID before Selkies and Claude Desktop start. Claude Code refuses bypass mode
|
||||
under an effective root UID.
|
||||
- **gnome-keyring** provides the Secret Service backend Electron needs to
|
||||
persist sign-in and dispatch permission grants across restarts.
|
||||
|
||||
@@ -63,6 +67,8 @@ Git synchronization hooks. A repository is indexed only when it is listed in
|
||||
- Persistent sign-in through a bundled, auto-unlocked gnome-keyring.
|
||||
- Configurable Claude Code permissions: strict prompts, automatic safe-action
|
||||
approval, or explicit full bypass for trusted installations.
|
||||
- Automatic non-root runtime enforcement for bypass mode, including root-console
|
||||
wrapper launches.
|
||||
- Optional runtime Claude Desktop updates from Anthropic's apt repository.
|
||||
- Optional extra apt and pip package installation (pip installs use `uv`).
|
||||
- Baked-in `git`, GitHub CLI (`gh`), `ripgrep`, `jq`, `shellcheck`, `yamllint`,
|
||||
@@ -74,17 +80,19 @@ Git synchronization hooks. A repository is indexed only when it is listed in
|
||||
Assistant.
|
||||
- Independent hourly savings reports for Headroom, RTK, and TokenSave.
|
||||
- `claude-tools-doctor.sh` diagnostics for binaries, routing, hooks, MCP
|
||||
registrations, project indexes, proxy health, permissions, and gains.
|
||||
registrations, project indexes, proxy health, permissions, runtime identity,
|
||||
and gains.
|
||||
- Low-power defaults for GPU mapping, Selkies frame rate, and volatile caches.
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Default | Description |
|
||||
| ------ | ------- | ----------- |
|
||||
| `PUID` / `PGID` | `0` / `0` | Numeric user and group applied by the LinuxServer initialization. |
|
||||
| `PUID` / `PGID` | `0` / `0` | Numeric user and group applied by LinuxServer initialization. In bypass mode, a root `PUID` is automatically replaced at runtime by an unused non-root UID while the configured group is retained. |
|
||||
| `TZ` | | Optional timezone, for example `Europe/Brussels`. |
|
||||
| `KEYBOARD` | | Optional Selkies keyboard layout. |
|
||||
| `PASSWORD` | | Optional password for direct Selkies ports. |
|
||||
| `SUDO_PASSWORD` | | LinuxServer.io convention: grants the `abc` user sudo access gated by this password. Sudo access is disabled by default when left unset. |
|
||||
| `DRINODE` | | Optional GPU device override for Selkies. |
|
||||
| `DNS_server` | `8.8.8.8` | DNS server used by the standard DNS module. |
|
||||
| `auto_update` | `true` | Upgrade `claude-desktop` from Anthropic's apt repository at startup. |
|
||||
@@ -122,9 +130,21 @@ permission_mode: auto
|
||||
`bypassPermissions` in the shared settings and
|
||||
`--dangerously-skip-permissions` for wrapper-launched sessions.
|
||||
|
||||
Claude Code does not permit bypass mode when its effective UID is `0`. If the
|
||||
add-on is configured with `PUID: 0`, selecting `bypass` remaps only the shared
|
||||
`abc` runtime account to an available non-root UID (preferring `1000`, then
|
||||
`911`) before storage ownership and Desktop startup. Its configured primary
|
||||
GID is retained, so group-based access to mounted Home Assistant paths remains
|
||||
available. Strict and auto modes keep the configured identity unchanged.
|
||||
|
||||
A root shell invoking `/usr/local/bin/claude` in bypass mode is also dropped to
|
||||
the remapped `abc` account. Directly invoking `/usr/bin/claude` as root still
|
||||
bypasses the add-on wrapper and will be rejected by Claude Code.
|
||||
|
||||
`bypass` gives Claude broad authority over all mounted writable data and every
|
||||
command or credential available inside the add-on. Enable it only in a trusted
|
||||
installation with trusted repositories and mounts.
|
||||
installation with trusted repositories and mounts. Mounted paths must remain
|
||||
accessible to the effective non-root UID or its retained group.
|
||||
|
||||
### TokenSave project example
|
||||
|
||||
@@ -171,10 +191,11 @@ Run the following inside the add-on through a custom script or container console
|
||||
claude-tools-doctor.sh
|
||||
```
|
||||
|
||||
The report checks the tool binaries, configuration switches, redacted MCP
|
||||
registrations, Claude hooks, permission mode, Headroom health, TokenSave indexes,
|
||||
routing, and recorded savings. It never prints MCP environment values because
|
||||
the Home Assistant MCP entry can contain a long-lived token.
|
||||
The report checks the tool binaries, configuration switches, configured and
|
||||
effective runtime identities, redacted MCP registrations, Claude hooks,
|
||||
permission mode, Headroom health, TokenSave indexes, routing, and recorded
|
||||
savings. It never prints MCP environment values because the Home Assistant MCP
|
||||
entry can contain a long-lived token.
|
||||
|
||||
The hourly report can also be invoked manually:
|
||||
|
||||
|
||||
@@ -13,8 +13,8 @@ environment:
|
||||
AUTO_GPU: "1"
|
||||
FM_HOME: /data/data
|
||||
HOME: /data/data
|
||||
PGID: "0"
|
||||
PUID: "0"
|
||||
PGID: "1000"
|
||||
PUID: "1000"
|
||||
SELKIES_FRAMERATE: "30"
|
||||
START_DOCKER: "false"
|
||||
TITLE: Claude Desktop
|
||||
@@ -35,8 +35,6 @@ options:
|
||||
env_vars: []
|
||||
DNS_server: 8.8.8.8
|
||||
data_location: /data/data
|
||||
PGID: 0
|
||||
PUID: 0
|
||||
additional_apps: ""
|
||||
additional_pip: ""
|
||||
auto_update: true
|
||||
@@ -76,12 +74,15 @@ schema:
|
||||
DRINODE: list(/dev/dri/card0|/dev/dri/card1|/dev/dri/card2|/dev/dri/renderD128|/dev/dri/renderD129|)?
|
||||
KEYBOARD: list(da-dk-qwerty|de-de-qwertz|en-gb-qwerty|en-us-qwerty|es-es-qwerty|fr-ch-qwertz|fr-fr-azerty|it-it-qwerty|ja-jp-qwerty|pt-br-qwerty|sv-se-qwerty|tr-tr-qwerty)?
|
||||
PASSWORD: str?
|
||||
PGID: int
|
||||
PUID: int
|
||||
SUDO_PASSWORD: password?
|
||||
TZ: match([A-Z][a-z]*./[A-Z][a-z]*.)?
|
||||
additional_apps: str?
|
||||
additional_pip: str?
|
||||
auto_update: bool?
|
||||
cifsdomain: str?
|
||||
cifspassword: str?
|
||||
cifsusername: str?
|
||||
localdisks: str?
|
||||
networkdisks: str?
|
||||
github_email: str?
|
||||
enable_ha_mcp: bool?
|
||||
ha_mcp_url: str?
|
||||
@@ -103,5 +104,5 @@ slug: claude_desktop
|
||||
tmpfs: true
|
||||
udev: true
|
||||
url: https://github.com/alexbelgium/hassio-addons
|
||||
version: "1.20"
|
||||
version: "1.23"
|
||||
video: true
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
set -o pipefail
|
||||
|
||||
# Claude Code deliberately refuses bypass-permissions mode when its effective UID is 0.
|
||||
# The add-on historically defaults PUID to 0, so switch the shared `abc` desktop user to
|
||||
# an unused non-root UID before storage ownership and Selkies runtime directories are set up.
|
||||
# Keep abc's configured primary group (commonly group 0) so existing group-based access to
|
||||
# Home Assistant mounts is preserved. Strict and auto permission modes are unchanged.
|
||||
if [ "$(bashio::config 'permission_mode')" != "bypass" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
CURRENT_UID="$(id -u abc)"
|
||||
if [ "$CURRENT_UID" -ne 0 ]; then
|
||||
bashio::log.info "Claude bypass runtime already uses non-root UID ${CURRENT_UID}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
find_available_uid() {
|
||||
local candidate owner
|
||||
for candidate in 1000 911 $(seq 1001 1099); do
|
||||
owner="$(getent passwd "$candidate" | cut -d: -f1 || true)"
|
||||
if [ -z "$owner" ] || [ "$owner" = "abc" ]; then
|
||||
printf '%s' "$candidate"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
TARGET_UID="$(find_available_uid || true)"
|
||||
if [ -z "$TARGET_UID" ]; then
|
||||
bashio::exit.nok "Claude bypass mode requires a non-root runtime user, but no free fallback UID was found"
|
||||
fi
|
||||
|
||||
usermod --uid "$TARGET_UID" abc
|
||||
|
||||
if [ "$(id -u abc)" -eq 0 ]; then
|
||||
bashio::exit.nok "Unable to switch the Claude Desktop runtime away from root for bypass mode"
|
||||
fi
|
||||
|
||||
mkdir -p /run/s6/container_environment
|
||||
printf '%s' "$TARGET_UID" > /run/s6/container_environment/CLAUDE_RUNTIME_UID
|
||||
printf '%s' "$(id -g abc)" > /run/s6/container_environment/CLAUDE_RUNTIME_GID
|
||||
|
||||
bashio::log.warning "Claude bypass mode cannot run as root; remapped abc from UID 0 to UID ${TARGET_UID} (GID $(id -g abc))"
|
||||
@@ -3,9 +3,10 @@
|
||||
# shellcheck disable=SC2046
|
||||
set -e
|
||||
|
||||
# Define user
|
||||
PUID=$(bashio::config "PUID")
|
||||
PGID=$(bashio::config "PGID")
|
||||
# Use the effective shared desktop user identity. In bypass mode an earlier init script may
|
||||
# remap abc away from UID 0 because Claude Code rejects bypass permissions when run as root.
|
||||
PUID="$(id -u abc)"
|
||||
PGID="$(id -g abc)"
|
||||
|
||||
# Check data location
|
||||
LOCATION="$(bashio::config 'data_location')"
|
||||
|
||||
@@ -2,11 +2,9 @@
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
if bashio::config.true 'auto_update'; then
|
||||
bashio::log.info "Checking for Claude Desktop updates..."
|
||||
if apt-get update -o Acquire::http::Timeout=10 -o Acquire::https::Timeout=10 &> /dev/null && apt-get install -y --only-upgrade claude-desktop &> /dev/null; then
|
||||
bashio::log.info "Claude Desktop version: $(dpkg-query -W -f='${Version}' claude-desktop)"
|
||||
else
|
||||
bashio::log.warning "Update check failed (offline?), keeping current version"
|
||||
fi
|
||||
bashio::log.info "Checking for Claude Desktop updates..."
|
||||
if apt-get update -o Acquire::http::Timeout=10 -o Acquire::https::Timeout=10 &> /dev/null && apt-get install -y --only-upgrade claude-desktop &> /dev/null; then
|
||||
bashio::log.info "Claude Desktop version: $(dpkg-query -W -f='${Version}' claude-desktop)"
|
||||
else
|
||||
bashio::log.warning "Update check failed (offline?), keeping current version"
|
||||
fi
|
||||
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/with-contenv bashio
|
||||
# shellcheck shell=bash
|
||||
set -e
|
||||
|
||||
# Earlier configuration scripts intentionally run as root and may use the configured PUID/PGID
|
||||
# values when returning files to the runtime user. In bypass mode PUID can still be configured as
|
||||
# 0 even though 19-claude_bypass_runtime.sh remapped abc to a non-root UID. Reconcile ownership
|
||||
# with the effective desktop identity after all Claude configuration writes are complete.
|
||||
RUNTIME_UID="$(id -u abc)"
|
||||
RUNTIME_GID="$(id -g abc)"
|
||||
|
||||
for managed_path in "$HOME/.claude" "$HOME/.claude.json" "$HOME/.config/Claude"; do
|
||||
if [ -e "$managed_path" ]; then
|
||||
chown -R -- "${RUNTIME_UID}:${RUNTIME_GID}" "$managed_path" \
|
||||
|| bashio::log.warning "Unable to set effective runtime ownership on $managed_path"
|
||||
fi
|
||||
done
|
||||
@@ -27,6 +27,17 @@ if [ ! -x "$REAL_CLAUDE" ]; then
|
||||
exit 127
|
||||
fi
|
||||
|
||||
# Claude Code rejects bypass mode when the effective UID is 0. Normal Desktop sessions run
|
||||
# as abc, which startup remaps to a non-root UID when bypass is selected. Also handle a user
|
||||
# invoking this wrapper directly from a root container console by dropping to abc here.
|
||||
if [ "$PERMISSION_MODE" = "bypass" ] && [ "$(id -u)" -eq 0 ]; then
|
||||
if command -v s6-setuidgid > /dev/null 2>&1 && [ "$(id -u abc)" -ne 0 ]; then
|
||||
exec s6-setuidgid abc "$0" "$@"
|
||||
fi
|
||||
echo "claude wrapper: bypass mode requires a non-root runtime user, but abc is still UID 0" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if bashio::config.true 'install_headroom' && bashio::config.true 'headroom_wrap_claude_code'; then
|
||||
if [ -x "$HEADROOM_BIN" ] && curl -fsS --max-time 2 "${HEADROOM_URL}/health" > /dev/null 2>&1; then
|
||||
# Put /usr/bin before /usr/local/bin while Headroom resolves its upstream `claude`
|
||||
|
||||
@@ -26,6 +26,18 @@ for option in permission_mode install_headroom headroom_wrap_claude_code expose_
|
||||
printf '%-30s %s\n' "$option" "$(bashio::config "$option")"
|
||||
done
|
||||
|
||||
section "Runtime identity"
|
||||
printf '%-30s %s\n' "configured PUID:PGID" "$(bashio::config 'PUID'):$(bashio::config 'PGID')"
|
||||
printf '%-30s %s\n' "effective abc UID:GID" "$(id -u abc):$(id -g abc)"
|
||||
printf '%-30s %s\n' "current process UID:GID" "$(id -u):$(id -g)"
|
||||
if [ "$(bashio::config 'permission_mode')" = "bypass" ]; then
|
||||
if [ "$(id -u abc)" -eq 0 ]; then
|
||||
echo "bypass runtime: ERROR - Claude Code will reject bypass permissions while abc is root"
|
||||
else
|
||||
echo "bypass runtime: OK - Claude Desktop and Cowork run as a non-root UID"
|
||||
fi
|
||||
fi
|
||||
|
||||
section "Claude Code permission state"
|
||||
python3 - <<'PY'
|
||||
import json
|
||||
|
||||
Reference in new issue
Block a user