Skip to content

fix(gateway): harden Docker/container gateway pathway - #8573

Closed
alt-glitch wants to merge 3 commits into
mainfrom
fix/gateway-no-systemctl
Closed

fix(gateway): harden Docker/container gateway pathway#8573
alt-glitch wants to merge 3 commits into
mainfrom
fix/gateway-no-systemctl

Conversation

@alt-glitch

@alt-glitch alt-glitch commented Apr 12, 2026

Copy link
Copy Markdown
Collaborator

What does this PR do?

Fixes the FileNotFoundError: systemctl crash when running gateway commands inside Docker containers, and goes further to make the entire CLI Docker-aware — correct status output, helpful guidance instead of generic errors, and defense-in-depth against any future systemctl calls leaking through.

Before: hermes gateway install inside Docker crashed or showed "not supported" with exit code 1. hermes status lied with "Manager: systemd (user)". hermes dump showed "gateway: unknown".

After: All gateway commands detect containers, show Docker-specific guidance (restart policies, docker restart, hermes gateway run), and exit cleanly. Status and dump report accurate container-aware information.

Related Issue

Fixes #7420

Type of Change

  • 🐛 Bug fix (non-breaking change that fixes an issue)
  • ♻️ Refactor (no behavior change)
  • ✅ Tests (adding or improving test coverage)

Changes Made

Core: centralized container detection

  • hermes_constants.py — Added is_container() with process-lifetime caching. Checks /.dockerenv, /run/.containerenv, /proc/1/cgroup for Docker/Podman/LXC markers. Same pattern as existing is_wsl() and is_termux().
  • hermes_cli/config.py — Deduplicated _is_inside_container() to delegate to the new is_container().
  • tools/voice_mode.py — Replaced inline /.dockerenv check with is_container().

Gateway: defense-in-depth

  • hermes_cli/gateway.py — Added _run_systemctl() wrapper that catches FileNotFoundError and raises RuntimeError with container-aware messaging. Replaced all 10 bare subprocess.run(_systemctl_cmd(...)) call sites. Added is_container() branches in gateway_command() for install, uninstall, and start subcommands — these now exit 0 with Docker-specific guidance instead of exit 1 with "not supported".

CLI: accurate Docker status

  • hermes_cli/status.pyhermes status now shows "Manager: docker (foreground)" inside containers, using find_gateway_pids() instead of systemctl.
  • hermes_cli/dump.pyhermes dump now shows "running (docker, pid N)" or "stopped (docker)" instead of "unknown".
  • hermes_cli/setup.pysetup_gateway() shows Docker restart policy instructions in containers.

Tests

  • tests/test_hermes_constants.py — 5 tests for is_container(): dockerenv, containerenv, cgroup, negative, caching.
  • tests/hermes_cli/test_gateway_service.py — 5 tests: _run_systemctl error/passthrough, install/uninstall/start Docker guidance (exit 0 + correct output).
  • tests/hermes_cli/test_setup.py — 1 test: setup_gateway shows Docker instructions in containers.

How to Test

Unit tests

pytest tests/test_hermes_constants.py tests/hermes_cli/test_gateway_service.py tests/hermes_cli/test_setup.py -x
# 99 passed

Docker end-to-end

docker build -t hermes-test -f Dockerfile.test .
docker run --rm --entrypoint hermes hermes-test gateway install   # exit 0, Docker guidance
docker run --rm --entrypoint hermes hermes-test gateway uninstall # exit 0, Docker guidance
docker run --rm --entrypoint hermes hermes-test gateway start     # exit 0, Docker guidance
docker run --rm --entrypoint hermes hermes-test gateway status    # "not running" (no crash)
docker run --rm --entrypoint hermes hermes-test status            # "Manager: docker (foreground)"
docker run --rm --entrypoint hermes hermes-test dump              # "gateway: stopped (docker)"

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits
  • I searched for existing PRs to make sure this isn't a duplicate
  • My PR contains only changes related to this fix/feature
  • I've run pytest tests/ -q and all tests pass
  • I've added tests for my changes
  • I've tested on my platform: macOS 15 (unit tests) + Docker debian:13.4/aarch64 (e2e)

Documentation & Housekeeping

  • I've considered cross-platform impact — changes only affect Linux container detection paths; macOS/Windows unaffected
  • N/A for config keys, tool schemas, architecture docs

dlkakbs and others added 3 commits April 12, 2026 11:58
Extract `is_container()` detection logic from scattered locations
(`config.py`, `voice_mode.py`) into a centralized, cached function in
`hermes_constants.py`. This follows the same pattern as `is_wsl()` and
`is_termux()` — checking `/.dockerenv`, `/run/.containerenv`, and cgroup
markers.

Update gateway status detection (`status.py`, `dump.py`) to use the new
utility and handle Docker/Podman differently from systemd-based systems.
Update setup guidance (`setup.py`) to show Docker restart instructions
when running in a container.

Add Dockerfile.test for CI integration testing and spec.md as a Python
module taste guide for contributors.
Remove `_is_inside_container()` from `hermes_cli/config.py` and migrate
callers to use `is_container()` from `hermes_constants`. This
centralizes
container environment detection in a single, reusable location.
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Supply Chain Risk Detected

This PR contains patterns commonly associated with supply chain attacks. This does not mean the PR is malicious — but these patterns require careful human review before merging.

⚠️ WARNING: Install hook files modified

These files can execute code during package installation or interpreter startup.

Files:

hermes_cli/setup.py
tests/hermes_cli/test_setup.py

Automated scan triggered by supply-chain-audit. If this is a false positive, a maintainer can approve after manual review.

@alt-glitch alt-glitch changed the title Fix/gateway no systemctl fix(gateway): harden Docker/container gateway pathway Apr 12, 2026
@teknium1

Copy link
Copy Markdown
Contributor

@alt-glitch — Salvaged your work in #8614 onto current main. Your authorship is preserved in the commit.

Changes from your original PR:

  • Removed spec.md (looked like personal notes that snuck in), Dockerfile.test, and the uv.lock changes (unrelated Matrix deps)
  • Kept everything else as-is — the is_container() centralization, _run_systemctl() wrapper, Docker-aware status/dump/setup, and all tests

All 113 targeted tests pass. Thanks for the thorough fix!

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.

[Bug]: No such file or directory: 'systemctl'

3 participants