Files
deepseek-harness/dsh-wrapper.sh
T
Miles WardandClaude Fable 5 acd81b2f79
Sync upstream and build images / sync-and-build (push) Failing after 22s
Self-healing volume ownership: no more manual chown, no more EACCES
A bind mount arrives with the host's ownership, so a freshly created appdata
directory killed dsh with EACCES on mkdir /home/node/.dsh/profiles/web. Only
root inside the container can fix that, so:

- docker-entrypoint.sh starts as root, aligns the node account with PUID/PGID
  (default 1000:1000, Unraid convention), takes ownership of the state volume
  when needed, then setpriv's down before exec'ing dsh. The network-reachable
  process is never root and no setuid binary is left behind. The workspace
  mount point is made writable but its CONTENTS are left alone unless
  DSH_CHOWN_WORKSPACE=1 — never silently rewrite ownership across user data.
- Dropped USER node (root is required to chown); dsh is wrapped so a root
   re-execs as PUID:PGID and cannot leave
  root-owned files in the volume. Wrapper resolves the real bin.js at build
  time and self-tests.
- Explicit --user is honored: ownership cannot be repaired, so the entrypoint
  verifies writability and exits with one actionable line instead of a Node
  stack trace.
- XDG_CONFIG_HOME pinned into the volume too; pnpm was reaching for
  /root/.config when HOME was unset.
- CI: labels now carry a recipe hash, and the freshness check cuts a -rN
  revision when the recipe changes — so an image fix reaches the pinned
  deployment without waiting for an upstream release.
- README/template: chown step removed, PUID/PGID/DSH_CHOWN_WORKSPACE
  documented, template pinned to 0.1.1-rc.2-r1.

Verified with a 23-case matrix: root-owned volume self-heals and serves 200,
already-correct volume skips the chown, 99:100 + PUID/PGID works, plugin
add/remove via root docker exec leaves no root-owned files, explicit --user
still works and fails clearly when it can't, both argument forms serve.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-09-11 12:00:30 -04:00

20 lines
771 B
Bash

#!/bin/sh
# `dsh` on PATH, wrapped so root invocations drop to the runtime user.
#
# The container starts as root (see docker-entrypoint.sh), which also makes
# `docker exec <container> dsh …` run as root by default — and the documented
# plugin workflow (`dsh plugin --profile web add …`) would then leave
# root-owned files in the state volume that dsh cannot read on its next start.
# Re-exec'ing as PUID:PGID keeps the volume consistent no matter how dsh is
# invoked. Set DSH_ALLOW_ROOT=1 to bypass (diagnostics only).
set -eu
BIN=__DSH_BIN__
if [ "$(id -u)" = 0 ] && [ "${DSH_ALLOW_ROOT:-0}" != 1 ]; then
exec setpriv --reuid "${PUID:-1000}" --regid "${PGID:-1000}" --init-groups \
env HOME=/home/node node "$BIN" "$@"
fi
exec node "$BIN" "$@"