mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-07-31 19:16:29 +00:00
Add a module-scoped `shared_container` fixture to tests/docker/conftest.py that boots one `sleep infinity` container per test module and tears it down at module exit. Convert read-only tests that previously used `docker run --rm --entrypoint sh/cat/test/su` (bypassing s6 to check static image properties) or `docker run -d` + `docker exec` (starting identical containers per test) to use `docker exec` on the shared container instead. Converted files: test_immutable_install_permissions.py — 2 throwaway runs → 2 execs test_license_file_present.py — 1 throwaway run → 1 exec test_tini_compat_shim.py — 1 throwaway run → 1 exec test_tui_prebuilt_bundle.py — 2 throwaway runs → 2 execs test_dump_build_sha.py — 2 throwaway runs → 2 execs test_immutable_install.py — 3 detached runs → 1 shared + 1 isolated test_dashboard.py — 2 detached runs → 0 (use shared) Local profiling shows docker run calls in these 7 files dropped from ~25 to 7 (the 7 are shared_container boots per module + the one test that needs a restart). Each eliminated `docker run` was paying 1-9s of s6 cont-init startup; the replacement `docker exec` calls average 0.10s — an ~50x speedup per operation. Tests that mutate state (restarts, config changes, gateway starts) still use their own containers via `container_name` + `start_container`.
138 lines
4.6 KiB
Python
138 lines
4.6 KiB
Python
"""Runtime smoke tests for Docker immutable install tree and install-method stamp.
|
||
|
||
Build the real image and verify at runtime:
|
||
|
||
1. /opt/hermes is not writable by the hermes user (immutable install tree)
|
||
2. PYTHONDONTWRITEBYTECODE and HERMES_DISABLE_LAZY_INSTALLS are set
|
||
3. /opt/hermes/.install_method contains "docker" (code-scoped stamp)
|
||
4. $HERMES_HOME/.install_method is NOT stamped as "docker" by stage2
|
||
5. A stale "docker" stamp in $HERMES_HOME is healed (removed) on boot
|
||
|
||
Tests 1–4 are read-only checks against the default container state and
|
||
share the module-scoped ``shared_container`` fixture. Test 5 mutates
|
||
state and triggers a restart, so it uses its own container.
|
||
"""
|
||
from __future__ import annotations
|
||
|
||
from tests.docker.conftest import (
|
||
docker_exec,
|
||
docker_exec_sh,
|
||
restart_container,
|
||
start_container,
|
||
)
|
||
|
||
|
||
def test_install_tree_not_writable_by_hermes(
|
||
shared_container: str,
|
||
) -> None:
|
||
"""The hermes user must not be able to modify /opt/hermes.
|
||
|
||
The install tree (source, venv, TUI bundle, node_modules) must remain
|
||
root-owned and non-writable so an agent session cannot self-modify
|
||
the installation and brick the gateway.
|
||
"""
|
||
r = docker_exec_sh(
|
||
shared_container,
|
||
# Try to create a file under /opt/hermes as the hermes user
|
||
"touch /opt/hermes/test_write 2>&1 && "
|
||
"echo WRITE_SUCCEEDED || echo WRITE_FAILED",
|
||
timeout=10,
|
||
)
|
||
assert "WRITE_FAILED" in r.stdout, (
|
||
f"hermes user can write to /opt/hermes (install tree not immutable): "
|
||
f"{r.stdout}"
|
||
)
|
||
|
||
# Also check a key subdirectory
|
||
r = docker_exec_sh(
|
||
shared_container,
|
||
"touch /opt/hermes/.venv/test_write 2>&1 && "
|
||
"echo WRITE_SUCCEEDED || echo WRITE_FAILED",
|
||
timeout=10,
|
||
)
|
||
assert "WRITE_FAILED" in r.stdout, (
|
||
f"hermes user can write to /opt/hermes/.venv: {r.stdout}"
|
||
)
|
||
|
||
|
||
def test_hermes_disable_lazy_installs_and_dont_write_bytecode(
|
||
shared_container: str,
|
||
) -> None:
|
||
"""The container must set PYTHONDONTWRITEBYTECODE and
|
||
HERMES_DISABLE_LAZY_INSTALLS=1 so no .pyc files are written to the
|
||
immutable install tree and no lazy installs attempt to modify it."""
|
||
r = docker_exec_sh(
|
||
shared_container,
|
||
'test "$PYTHONDONTWRITEBYTECODE" = "1" && '
|
||
'test "$HERMES_DISABLE_LAZY_INSTALLS" = "1" && '
|
||
'echo ENV_OK || echo ENV_MISSING',
|
||
timeout=10,
|
||
)
|
||
assert "ENV_OK" in r.stdout, (
|
||
f"expected PYTHONDONTWRITEBYTECODE=1 and "
|
||
f"HERMES_DISABLE_LAZY_INSTALLS=1, got: {r.stdout} stderr={r.stderr}"
|
||
)
|
||
|
||
|
||
def test_install_method_stamp_is_code_scoped(
|
||
shared_container: str,
|
||
) -> None:
|
||
"""The 'docker' install-method stamp must be baked at
|
||
/opt/hermes/.install_method (code-scoped), NOT in $HERMES_HOME."""
|
||
# Code-scoped stamp must exist and say "docker"
|
||
r = docker_exec_sh(
|
||
shared_container,
|
||
"cat /opt/hermes/.install_method",
|
||
timeout=10,
|
||
)
|
||
assert r.returncode == 0, (
|
||
f"/opt/hermes/.install_method not found: {r.stderr}"
|
||
)
|
||
assert r.stdout.strip() == "docker", (
|
||
f"expected 'docker' stamp, got: {r.stdout.strip()!r}"
|
||
)
|
||
|
||
# $HERMES_HOME must NOT have a 'docker' stamp
|
||
r = docker_exec_sh(
|
||
shared_container,
|
||
"cat /opt/data/.install_method 2>/dev/null || echo NONE",
|
||
timeout=10,
|
||
)
|
||
assert r.stdout.strip() != "docker", (
|
||
"$HERMES_HOME/.install_method is stamped 'docker' - stage2 must "
|
||
"not stamp the data volume (shared with host installs)"
|
||
)
|
||
|
||
|
||
def test_stale_docker_stamp_in_home_is_healed_on_boot(
|
||
built_image: str, container_name: str,
|
||
) -> None:
|
||
"""A stale 'docker' stamp left in $HERMES_HOME by an older image
|
||
must be removed on boot so shared homes self-heal."""
|
||
# Start container, write a stale stamp
|
||
start_container(built_image, container_name)
|
||
|
||
# Write a stale 'docker' stamp as root
|
||
docker_exec(
|
||
container_name, "sh", "-c",
|
||
"printf 'docker\\n' > /opt/data/.install_method",
|
||
user="root", timeout=5,
|
||
)
|
||
# Verify it exists
|
||
r = docker_exec_sh(container_name, "cat /opt/data/.install_method", timeout=5)
|
||
assert r.stdout.strip() == "docker"
|
||
|
||
# Restart - stage2 should heal it
|
||
restart_container(container_name)
|
||
|
||
# The stale stamp must be gone
|
||
r = docker_exec_sh(
|
||
container_name,
|
||
"test -f /opt/data/.install_method && "
|
||
"cat /opt/data/.install_method || echo HEALED",
|
||
timeout=10,
|
||
)
|
||
assert "HEALED" in r.stdout or r.stdout.strip() != "docker", (
|
||
f"stale 'docker' stamp in $HERMES_HOME was not healed on boot: "
|
||
f"{r.stdout}"
|
||
)
|