Salvage of #37928 (@sarvesh1327), reduced to the still-needed delta. `/opt/hermes/gateway` is a runtime-writable Python package: on first import the supervised gateway writes `__pycache__` beneath it, and the image does not set PYTHONDONTWRITEBYTECODE. When HERMES_UID/PUID is remapped at boot (e.g. Unraid 99), `usermod -u` only re-chowns the hermes home dir; the build trees under /opt/hermes keep the build-time UID (10000). main already chowns `.venv`, `ui-tui`, and `node_modules` on remap (#38556) but missed `gateway`, so the remapped gateway hits EACCES writing `__pycache__` (#27221). Add `/opt/hermes/gateway` to both chown sites — the Dockerfile build-time `chown -R hermes:hermes` line and the stage2-hook build-tree repair — so it tracks the remapped UID like the sibling trees. Differs from #37928 as submitted: dropped the `uid_gid_remapped` flag and the `|| [ "$uid_gid_remapped" = true ]` chown gate. main's #38556 already solved that half, and more correctly — it probes the actual tree ownership (`venv_owner != actual_hermes_uid`) rather than tracking same-boot remaps, which also catches pre-existing ownership drift and stays idempotent. Keeping #37928's flag would regress that. The salvage is the `gateway`-tree addition only. Verified end-to-end against a real image build: on baseline main a remap to UID 99 leaves `gateway` owned by 10000 and a write as uid 99 fails EACCES; with this change `gateway` is chowned to 99:100 and the write succeeds, while the default-uid (no-remap) path is unchanged. Fixes #27221. Co-authored-by: Sarvesh <sarveshagl1327@gmail.com>
44 lines
1.5 KiB
Python
44 lines
1.5 KiB
Python
"""contract test: dockerfile chowns runtime node_modules trees to hermes
|
|
|
|
regression guard for #18800. the container drops privileges to the hermes
|
|
user (uid 10000) in entrypoint.sh, then the TUI launcher's
|
|
_tui_need_npm_install() trips on every startup (see the
|
|
npm_config_install_links=false comment in the Dockerfile) and runs
|
|
`npm install` in /opt/hermes/ui-tui. that install fails with EACCES unless
|
|
the runtime node_modules trees are owned by hermes.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
from pathlib import Path
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
|
DOCKERFILE = REPO_ROOT / "Dockerfile"
|
|
|
|
|
|
def test_dockerfile_chowns_runtime_node_modules_to_hermes_user() -> None:
|
|
text = DOCKERFILE.read_text()
|
|
|
|
chown_lines = [
|
|
line for line in text.splitlines()
|
|
if "chown" in line and "hermes:hermes" in line
|
|
]
|
|
assert chown_lines, (
|
|
"Dockerfile must contain a chown -R hermes:hermes for the runtime "
|
|
"node_modules trees; see #18800"
|
|
)
|
|
|
|
chown_block = "\n".join(chown_lines)
|
|
|
|
# Runtime-mutable trees must be passed to the chown command.
|
|
# /opt/hermes/web is intentionally excluded: it is build-time only,
|
|
# because HERMES_WEB_DIST points at hermes_cli/web_dist for runtime.
|
|
for required_path in (
|
|
"/opt/hermes/ui-tui",
|
|
"/opt/hermes/node_modules",
|
|
"/opt/hermes/gateway",
|
|
):
|
|
assert required_path in chown_block, (
|
|
f"{required_path} must be passed to a chown -R hermes:hermes "
|
|
f"command in the Dockerfile (see #18800, #27221)"
|
|
)
|