Skip to content

Use s6-setuidgid for Hermes privilege drop#17

Merged
Pol-Lanski merged 2 commits into
mainfrom
copilot/fixinstall-gosu
Jun 4, 2026
Merged

Use s6-setuidgid for Hermes privilege drop#17
Pol-Lanski merged 2 commits into
mainfrom
copilot/fixinstall-gosu

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Jun 3, 2026

The package can enter a restart loop because entrypoint.sh still re-execs through gosu, but current upstream Hermes images no longer ship that binary. This change aligns the DAppNode wrapper with upstream Hermes by switching privilege drop to s6-setuidgid.

  • What changed

    • Added a drop_to_hermes() helper in entrypoint.sh
    • Replaced the direct gosu hermes ... re-exec with that helper
  • Privilege drop behavior

    • Uses s6-setuidgid when available on PATH
    • Falls back to /command/s6-setuidgid for s6-overlay layouts
    • Exits with a clear error if neither binary is present, instead of failing with env: 'gosu': No such file or directory
  • Why this matters

    • Matches the current upstream Hermes container model
    • Removes the stale dependency on gosu
    • Prevents the restart loop caused by the removed binary
drop_to_hermes() {
    if command -v s6-setuidgid >/dev/null 2>&1; then
        exec env HOME="$HERMES_HOME/home" USER=hermes LOGNAME=hermes s6-setuidgid hermes "$0" "$@"
    fi

    if [ -x /command/s6-setuidgid ]; then
        exec env HOME="$HERMES_HOME/home" USER=hermes LOGNAME=hermes /command/s6-setuidgid hermes "$0" "$@"
    fi

    echo "Error: s6-setuidgid not found; cannot drop root privileges." >&2
    exit 127
}
Original prompt

Create a pull request from the existing fix branch fix/install-gosu into main for repository dappnode/DAppNodePackage-Hermes-agent.

Context:

  • The package currently restarts with env: 'gosu': No such file or directory because entrypoint.sh calls gosu when dropping root privileges.
  • Latest upstream Hermes no longer bundles gosu; it uses s6-overlay's s6-setuidgid for privilege dropping.
  • A fix commit already exists on branch fix/install-gosu: 3ac8d84efad9eb31455a9371e6898b505dc694db.
  • The fix updates entrypoint.sh to use a drop_to_hermes() helper that tries s6-setuidgid on PATH, falls back to /command/s6-setuidgid, and fails clearly if neither is available.

Open a PR into main with a concise description explaining that this aligns the DAppNode package with latest upstream Hermes and fixes the restart loop caused by the removed gosu binary.

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: After running the package, I'm encountering this error (the package is in restart) :
Dropping root privileges
env: 'gosu': No such file or directory
Dropping root privileges
env: 'gosu': No such file or directory
Dropping root privileges
env: 'gosu': No such file or directory
Dropping root privileges
env: 'gosu': No such file or directory
Dropping root privileges
env: 'gosu': No such file or directory
Dropping root privileges
env: 'gosu': No such file or directory

How can I fix this?

Assistant: The package is restarting because entrypoint.sh calls gosu, but the Docker image does not install gosu.

The failing line is:

echo "Dropping root privileges"
exec env HOME="$HERMES_HOME/home" USER=hermes LOGNAME=hermes gosu hermes "$0" "$@"

But the current Dockerfile only installs ttyd and WhatsApp dependencies; it never installs gosu.

Fix

Add gosu installation to the Dockerfile after USER root:

ARG UPSTREAM_VERSION="latest"

FROM nousresearch/hermes-agent:${UPSTREAM_VERSION}

USER root

# Install runtime dependencies needed by entrypoint.sh
RUN apt-get update \
    && apt-get install -y --no-install-recommends gosu \
    && rm -rf /var/lib/apt/lists/*

# Install ttyd for web terminal (static binary from GitHub releases)
ADD --chmod=755 https://github.com/tsl0922/ttyd/releases/download/1.7.7/ttyd.x86_64 /usr/local/bin/ttyd

# Pre-install WhatsApp bridge dependencies
RUN cd /opt/hermes/scripts/whatsapp-bridge && npm install --omit=dev --no-audit --no-fund

Then rebuild and reinstall/restart the package.

If the base image is Alpine-based

If the build fails with apt-get: not found, use this instead:

RUN apk add --no-cache gosu

Why this happens

The entrypoint starts as root, prepares /opt/data, then tries to drop privileges to the hermes user using gosu. Since gosu is missing from the image, the entrypoint exits immediately, and DAppNode restarts the package repeatedly.

So the direct fix is: install gosu in the image, then rebuild the package.

User: why did it start asking for gosu when in the previous version it didn't?

Assistant: It started asking for gosu because the package’s entrypoint.sh was changed to match a newer upstream Hermes entrypoint pattern.

Previously, the DAppNode package ran everything directly as root/non-dropped user and did not call gosu. In the older entrypoint, there is no root privilege drop; it activates the venv immediately:

# --- Activate virtualenv ---
source "${INSTALL_DIR}/.venv/bin/activate"

In the newer entrypoint, a “root preflight and privilege drop” block was added. If the container starts as root, it fixes ownership of /opt/data, then re-execs itself as the hermes user using gosu:

# --- Root preflight and privilege drop ---
# Upstream Hermes starts the official image as root only long enough to repair
# the mounted data volume and then re-enters as the non-root `hermes` user.
if [ "$(id -u)" = "0" ]; then
    ...
    echo "Dropping root privileges"
    exec env HOME="$HERMES_HOME/home" USER=hermes LOGNAME=hermes gosu hermes "$0" "$@"
fi

The relevant repo history shows this happened in commit 25166b5c, titled “entrypoint improvements”, on May 8, 2026. The older version before that, commit d8cfd9c, had no gosu usage.

So the cause is:

  1. Dockerfile sets the container to run as root:
</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

Copilot AI changed the title [WIP] Fix restart loop by using s6-setuidgid in entrypoint.sh Use s6-setuidgid for Hermes privilege drop Jun 3, 2026
Copilot AI requested a review from Pol-Lanski June 3, 2026 09:09
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Jun 3, 2026

Dappnode bot has built and pinned the built packages to an IPFS node, for commit: 88bc79e

This is a development version and should only be installed for testing purposes.

  1. Package hermes-agent.dnp.dappnode.eth

Install link

Hash: /ipfs/Qmcb1RGeyH1UbmJFdULQFX133GPomxomS7VGpQQKypNGNH

(by dappnodebot/build-action)

@mgarciate
Copy link
Copy Markdown

@Pol-Lanski working again! 🚀

@Pol-Lanski Pol-Lanski marked this pull request as ready for review June 4, 2026 04:09
@Pol-Lanski Pol-Lanski merged commit 73fdbe3 into main Jun 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants