Skip to content

fix(docker): don't chown config.yaml after gosu drop (#15865)#16096

Merged
teknium1 merged 1 commit into
mainfrom
hermes/hermes-abf60275
Apr 26, 2026
Merged

fix(docker): don't chown config.yaml after gosu drop (#15865)#16096
teknium1 merged 1 commit into
mainfrom
hermes/hermes-abf60275

Conversation

@teknium1

Copy link
Copy Markdown
Contributor

Summary

Fixes chown: changing ownership of '/opt/data/config.yaml': Operation not permitted when running the docker image with -u $(id -u):$(id -g). Regression from b24d239 (Apr 15, v2026.4.23).

Root cause

The chown/chmod block for config.yaml lives in the entrypoint's post-gosu 'running as hermes' section, not the root section. When the container is started with an explicit -u flag, the root block (lines 12-46) is skipped entirely, execution falls through to line 72 as the caller's UID (non-root, not hermes), and chown hermes:hermes fails. Under set -e this aborts the whole startup.

Changes

  • docker/entrypoint.sh: move the config.yaml chown/chmod into the root block (before the gosu exec), add 2>/dev/null || true guards to match the -R chown on HERMES_HOME for rootless Podman compatibility.

Validation

Scenario Before After
docker run <image> setup (default, root start) works works
docker run -u $(id -u):$(id -g) <image> setup "Operation not permitted", aborts works
Rootless Podman (root-in-container but no host chown privilege) works works (silent failure)

Local E2E harness confirms chown <other-user> under set -e with the || true guard does not abort the script.

Closes #15865

The chown/chmod block on config.yaml was added in b24d239 to keep the
file readable by the hermes runtime user, but it sat in the post-gosu
'running as hermes' section of the entrypoint. That meant:

1. Default `docker run <image>` — container starts as root, entrypoint
   drops to hermes via gosu, then non-root hermes tries to chown the
   file to hermes. Works by coincidence because the file was just
   created by root during volume setup and gosu target == target owner.
2. `docker run -u $(id -u):$(id -g) <image>` (#15865) — container
   starts as the caller's UID. The root block is skipped entirely, we
   land in the hermes section as some arbitrary non-root user, and
   chown to 'hermes' fails with 'Operation not permitted'. Script
   aborts under `set -e`.

Move the chown/chmod into the root block (before the gosu exec) where
it actually has privilege, and guard with `2>/dev/null || true` so
rootless Podman (where even in-container root lacks host-side chown
rights) doesn't abort either.

Closes #15865
@teknium1 teknium1 merged commit 9ef1ae1 into main Apr 26, 2026
9 of 10 checks passed
@teknium1 teknium1 deleted the hermes/hermes-abf60275 branch April 26, 2026 15:27
@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists area/docker Docker image, Compose, packaging labels Apr 26, 2026
mayssamj pushed a commit to mayssamj/hermes-agent that referenced this pull request Apr 26, 2026
) (NousResearch#16096)

The chown/chmod block on config.yaml was added in b24d239 to keep the
file readable by the hermes runtime user, but it sat in the post-gosu
'running as hermes' section of the entrypoint. That meant:

1. Default `docker run <image>` — container starts as root, entrypoint
   drops to hermes via gosu, then non-root hermes tries to chown the
   file to hermes. Works by coincidence because the file was just
   created by root during volume setup and gosu target == target owner.
2. `docker run -u $(id -u):$(id -g) <image>` (NousResearch#15865) — container
   starts as the caller's UID. The root block is skipped entirely, we
   land in the hermes section as some arbitrary non-root user, and
   chown to 'hermes' fails with 'Operation not permitted'. Script
   aborts under `set -e`.

Move the chown/chmod into the root block (before the gosu exec) where
it actually has privilege, and guard with `2>/dev/null || true` so
rootless Podman (where even in-container root lacks host-side chown
rights) doesn't abort either.

Closes NousResearch#15865
ulasbilgen pushed a commit to ulasbilgen/hermes-adhd-agent that referenced this pull request May 1, 2026
) (NousResearch#16096)

The chown/chmod block on config.yaml was added in 647518a to keep the
file readable by the hermes runtime user, but it sat in the post-gosu
'running as hermes' section of the entrypoint. That meant:

1. Default `docker run <image>` — container starts as root, entrypoint
   drops to hermes via gosu, then non-root hermes tries to chown the
   file to hermes. Works by coincidence because the file was just
   created by root during volume setup and gosu target == target owner.
2. `docker run -u $(id -u):$(id -g) <image>` (NousResearch#15865) — container
   starts as the caller's UID. The root block is skipped entirely, we
   land in the hermes section as some arbitrary non-root user, and
   chown to 'hermes' fails with 'Operation not permitted'. Script
   aborts under `set -e`.

Move the chown/chmod into the root block (before the gosu exec) where
it actually has privilege, and guard with `2>/dev/null || true` so
rootless Podman (where even in-container root lacks host-side chown
rights) doesn't abort either.

Closes NousResearch#15865
donald131 pushed a commit to donald131/hermes-agent that referenced this pull request May 2, 2026
) (NousResearch#16096)

The chown/chmod block on config.yaml was added in b24d239 to keep the
file readable by the hermes runtime user, but it sat in the post-gosu
'running as hermes' section of the entrypoint. That meant:

1. Default `docker run <image>` — container starts as root, entrypoint
   drops to hermes via gosu, then non-root hermes tries to chown the
   file to hermes. Works by coincidence because the file was just
   created by root during volume setup and gosu target == target owner.
2. `docker run -u $(id -u):$(id -g) <image>` (NousResearch#15865) — container
   starts as the caller's UID. The root block is skipped entirely, we
   land in the hermes section as some arbitrary non-root user, and
   chown to 'hermes' fails with 'Operation not permitted'. Script
   aborts under `set -e`.

Move the chown/chmod into the root block (before the gosu exec) where
it actually has privilege, and guard with `2>/dev/null || true` so
rootless Podman (where even in-container root lacks host-side chown
rights) doesn't abort either.

Closes NousResearch#15865
02356abc pushed a commit to 02356abc/hermes-agent that referenced this pull request May 14, 2026
) (NousResearch#16096)

The chown/chmod block on config.yaml was added in b24d239 to keep the
file readable by the hermes runtime user, but it sat in the post-gosu
'running as hermes' section of the entrypoint. That meant:

1. Default `docker run <image>` — container starts as root, entrypoint
   drops to hermes via gosu, then non-root hermes tries to chown the
   file to hermes. Works by coincidence because the file was just
   created by root during volume setup and gosu target == target owner.
2. `docker run -u $(id -u):$(id -g) <image>` (NousResearch#15865) — container
   starts as the caller's UID. The root block is skipped entirely, we
   land in the hermes section as some arbitrary non-root user, and
   chown to 'hermes' fails with 'Operation not permitted'. Script
   aborts under `set -e`.

Move the chown/chmod into the root block (before the gosu exec) where
it actually has privilege, and guard with `2>/dev/null || true` so
rootless Podman (where even in-container root lacks host-side chown
rights) doesn't abort either.

Closes NousResearch#15865
dannyJ848 pushed a commit to dannyJ848/hermes-agent that referenced this pull request May 17, 2026
) (NousResearch#16096)

The chown/chmod block on config.yaml was added in ae9d2c4 to keep the
file readable by the hermes runtime user, but it sat in the post-gosu
'running as hermes' section of the entrypoint. That meant:

1. Default `docker run <image>` — container starts as root, entrypoint
   drops to hermes via gosu, then non-root hermes tries to chown the
   file to hermes. Works by coincidence because the file was just
   created by root during volume setup and gosu target == target owner.
2. `docker run -u $(id -u):$(id -g) <image>` (NousResearch#15865) — container
   starts as the caller's UID. The root block is skipped entirely, we
   land in the hermes section as some arbitrary non-root user, and
   chown to 'hermes' fails with 'Operation not permitted'. Script
   aborts under `set -e`.

Move the chown/chmod into the root block (before the gosu exec) where
it actually has privilege, and guard with `2>/dev/null || true` so
rootless Podman (where even in-container root lacks host-side chown
rights) doesn't abort either.

Closes NousResearch#15865
gweeteve pushed a commit to gweeteve/hermes-agent that referenced this pull request Jun 2, 2026
) (NousResearch#16096)

The chown/chmod block on config.yaml was added in b24d239 to keep the
file readable by the hermes runtime user, but it sat in the post-gosu
'running as hermes' section of the entrypoint. That meant:

1. Default `docker run <image>` — container starts as root, entrypoint
   drops to hermes via gosu, then non-root hermes tries to chown the
   file to hermes. Works by coincidence because the file was just
   created by root during volume setup and gosu target == target owner.
2. `docker run -u $(id -u):$(id -g) <image>` (NousResearch#15865) — container
   starts as the caller's UID. The root block is skipped entirely, we
   land in the hermes section as some arbitrary non-root user, and
   chown to 'hermes' fails with 'Operation not permitted'. Script
   aborts under `set -e`.

Move the chown/chmod into the root block (before the gosu exec) where
it actually has privilege, and guard with `2>/dev/null || true` so
rootless Podman (where even in-container root lacks host-side chown
rights) doesn't abort either.

Closes NousResearch#15865
Egavasyug pushed a commit to Egavasyug/hermes-agent that referenced this pull request Jun 10, 2026
) (NousResearch#16096)

The chown/chmod block on config.yaml was added in 6436a59 to keep the
file readable by the hermes runtime user, but it sat in the post-gosu
'running as hermes' section of the entrypoint. That meant:

1. Default `docker run <image>` — container starts as root, entrypoint
   drops to hermes via gosu, then non-root hermes tries to chown the
   file to hermes. Works by coincidence because the file was just
   created by root during volume setup and gosu target == target owner.
2. `docker run -u $(id -u):$(id -g) <image>` (NousResearch#15865) — container
   starts as the caller's UID. The root block is skipped entirely, we
   land in the hermes section as some arbitrary non-root user, and
   chown to 'hermes' fails with 'Operation not permitted'. Script
   aborts under `set -e`.

Move the chown/chmod into the root block (before the gosu exec) where
it actually has privilege, and guard with `2>/dev/null || true` so
rootless Podman (where even in-container root lacks host-side chown
rights) doesn't abort either.

Closes NousResearch#15865
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docker Docker image, Compose, packaging P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Permission issue with docker image v2026.4.23

2 participants