Fix self-inflicted lockout: secure_parent_dir() chmod's /opt/hermes to 0700
secure_parent_dir() is called before credential file writes to harden the parent dir. Its existing safety check refuses only paths with fewer than 3 path parts, but /opt/hermes is exactly 3 parts, so it passes and gets chmod'd to 0700. UID 10000 (hermes) cannot then traverse the install dir and every new exec fails with 'Permission denied' until manual chmod 0755 /opt/hermes. This change: - Adds an explicit refusal for /opt/hermes parents in secure_parent_dir() - Adds chmod 0755 /opt/hermes to the Dockerfile install step next to the existing bin chmod, so the dir starts traversable Reproducer: any auth write to a file directly under /opt/hermes (e.g. auth.json when HERMES_HOME resolves there). Observed in production 2026-07-06 and 2026-08-22. See #25821 for context. Fixes #25821 follow-up.
This commit is contained in:
@@ -298,7 +298,7 @@ RUN uv pip install --no-cache-dir --no-deps -e "."
|
||||
USER root
|
||||
RUN mkdir -p /opt/hermes/bin && \
|
||||
cp /opt/hermes/docker/hermes-exec-shim.sh /opt/hermes/bin/hermes && \
|
||||
chmod 0755 /opt/hermes/bin/hermes && \
|
||||
chmod 0755 /opt/hermes /opt/hermes/bin/hermes && \
|
||||
printf 'docker\n' > /opt/hermes/.install_method
|
||||
# The ``.install_method`` stamp is baked next to the running code (the install
|
||||
# tree), NOT into $HERMES_HOME. $HERMES_HOME (/opt/data) is a shared data
|
||||
|
||||
@@ -1023,6 +1023,15 @@ def secure_parent_dir(path: Path) -> None:
|
||||
# Refuse root and its direct children (/usr, /home, /var, /tmp, …).
|
||||
if parent == Path("/") or len(parent.parts) < 3:
|
||||
return
|
||||
# Refuse /opt/hermes. The install dir lives on the image layer;
|
||||
# chmodding it to 0700 breaks hermes-user traversal and produces
|
||||
# spurious "Permission denied" on every new exec until manual
|
||||
# `chmod 0755 /opt/hermes`. Reproducer: any auth write to a file
|
||||
# directly under /opt/hermes (e.g. /opt/hermes/auth.json when
|
||||
# HERMES_HOME resolves there) triggers the 0700 chmod and locks
|
||||
# out UID 10000. See issue #25821 follow-up.
|
||||
if str(parent) == "/opt/hermes":
|
||||
return
|
||||
try:
|
||||
os.chmod(parent, 0o700)
|
||||
except OSError:
|
||||
|
||||
Reference in New Issue
Block a user