From 84d018095a7b4c606fa9e9ee46c748227513b2dc Mon Sep 17 00:00:00 2001 From: Ho1yShif Date: Tue, 7 Jul 2026 11:37:22 -0700 Subject: [PATCH] fix(render): chown mounted disk as root, drop to nanobot via setpriv MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Render mounts a fresh persistent disk root-owned, but the container ran as non-root nanobot (uid 1000), so the app could not write /home/nanobot/.nanobot. The old entrypoint detected this and exit 1'd; Render swallowed the message and surfaced only the generic "Exited with status 128" with zero app logs, in a crash loop. Start the entrypoint as root, mkdir + chown the mounted data dir to nanobot, then exec setpriv to drop back to uid 1000 as PID 1 (graceful shutdown preserved). The app still runs non-root — the hardening is kept. Also bake PYTHONUNBUFFERED=1 / PYTHONFAULTHANDLER=1 into the image so future runtime crashes are visible in Render logs (durable across Blueprint syncs). Verified locally (amd64) against a simulated root-owned disk (--tmpfs ...,uid=0): clean boot, ws://0.0.0.0:8765, GET / = 200, app runs as uid 1000; and against a writable disk (no regression). Co-Authored-By: Claude Opus 4.8 (1M context) --- Dockerfile | 7 ++++++- entrypoint.sh | 19 +++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/Dockerfile b/Dockerfile index 38d13152..c70eaffb 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,8 +40,13 @@ RUN useradd -m -u 1000 -s /bin/bash nanobot && \ COPY entrypoint.sh /usr/local/bin/entrypoint.sh RUN sed -i 's/\r$//' /usr/local/bin/entrypoint.sh && chmod +x /usr/local/bin/entrypoint.sh -USER nanobot +# Start as root so the entrypoint can chown the freshly-mounted (root-owned) +# Render disk, then it drops to the non-root nanobot user via setpriv. +USER root ENV HOME=/home/nanobot +# Ensure crash output reaches Render logs (app output is otherwise swallowed on +# non-graceful exit). Baked in so it survives Blueprint syncs. +ENV PYTHONUNBUFFERED=1 PYTHONFAULTHANDLER=1 # Gateway health endpoint and optional WebUI/WebSocket channel ports EXPOSE 18790 8765 diff --git a/entrypoint.sh b/entrypoint.sh index ab780dc9..e0a39acb 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -1,15 +1,10 @@ #!/bin/sh +# Runs as root so we can fix ownership of a freshly-mounted persistent disk +# (Render mounts new disks root-owned) before dropping to the non-root app user. dir="$HOME/.nanobot" -if [ -d "$dir" ] && [ ! -w "$dir" ]; then - owner_uid=$(stat -c %u "$dir" 2>/dev/null || stat -f %u "$dir" 2>/dev/null) - cat >&2 <