Skip to content

fix(agent): probe container honors docker_network egress control (#76906) - #76926

Open
a-yeyang wants to merge 1 commit into
NousResearch:mainfrom
a-yeyang:fix/probe-docker-network-egress
Open

fix(agent): probe container honors docker_network egress control (#76906)#76926
a-yeyang wants to merge 1 commit into
NousResearch:mainfrom
a-yeyang:fix/probe-docker-network-egress

Conversation

@a-yeyang

@a-yeyang a-yeyang commented Aug 2, 2026

Copy link
Copy Markdown

What does this PR do?

_probe_remote_backend() in agent/prompt_builder.py runs a tiny introspection command inside the configured terminal backend to describe it in the system prompt. For container backends it assembles its own container_config dict — but it omits docker_network. That key then falls through to the True default in _create_environment, so the prompt-backend-probe container comes up on bridge even when the operator has set docker_network: false / TERMINAL_DOCKER_NETWORK=false as an egress control.

The agent's own shell container is air-gapped correctly (the live terminal path in tools/terminal_tool.py passes docker_network); this second probe container is not, and it inherits the same docker_volumes — so whatever the operator mounts for the agent (document trees, credential files) is present in a container with unrestricted egress. The setting is silently half-applied.

Fix: forward config.get("docker_network", True) into the probe's container_config, exactly as the live terminal path already does. One-line behavioral change; the probe now honors the same egress toggle as the agent shell.

Related Issue

Fixes #76906

Type of Change

  • 🔒 Security fix

(Bounded today — _resolve_container_task_id collapses everything to default and the probe runs a fixed printf/uname with no untrusted input — but it defeats an operator's egress control and mounts the same volumes in a networked container, so it's a real hardening gap.)

Changes Made

  • agent/prompt_builder.py_probe_remote_backend: add "docker_network": config.get("docker_network", True) to the probe's container_config, mirroring tools/terminal_tool.py.
  • tests/agent/test_prompt_builder.pytest_probe_remote_backend_honors_docker_network_false: with TERMINAL_DOCKER_NETWORK=false, patch the real _create_environment and assert the probe's container_config carries docker_network=False.

How to Test

  1. Configure a docker terminal backend with docker_network: false (or TERMINAL_DOCKER_NETWORK=false) and a docker_volumes mount.
  2. Trigger the backend probe (start a session so the system prompt is built).
  3. Before: docker ps shows two containers; docker inspect <probe> --format '{{.HostConfig.NetworkMode}}' is bridge (default). After: the probe container's NetworkMode is none, matching the agent shell.

Automated:

scripts/run_tests.sh tests/agent/test_prompt_builder.py -q

I confirmed the new test fails on main (probe container_config has no docker_network) and passes with this change. Full tests/agent/test_prompt_builder.py: 56 passed, 1 skipped.

Checklist

Code

  • I've read the Contributing Guide
  • My commit messages follow Conventional Commits (fix(agent):)
  • I searched for existing PRs to make sure this isn't a duplicate (no open PR addresses the probe's missing docker_network)
  • My PR contains only changes related to this fix
  • I've run the relevant tests and they pass
  • I've added tests for my changes
  • I've tested on my platform: macOS 15 (Darwin 24.6.0), Python 3.12

Documentation & Housekeeping

  • Documentation — N/A (no new config key; docker_network already documented, this makes the probe honor it)
  • cli-config.yaml.example — N/A (no new/changed keys)
  • CONTRIBUTING.md / AGENTS.md — N/A
  • Cross-platform impact — Docker-backend config only; no OS-specific code paths
  • Tool descriptions/schemas — N/A

…sResearch#76906)

`_probe_remote_backend()` builds its own container_config for the
`prompt-backend-probe` container but omitted `docker_network`. The key
therefore fell through to the `True` default in `_create_environment`, so
the probe container came up networked (on `bridge`) even when the operator
set `docker_network: false` / `TERMINAL_DOCKER_NETWORK=false` as an egress
control — while inheriting the agent's `docker_volumes` (document trees,
mounted credential files). The agent's own shell container was air-gapped
correctly; this second container was not, so the setting was silently
half-applied.

Fix: forward `config.get("docker_network", True)` into the probe's
container_config, mirroring the live terminal path in
tools/terminal_tool.py.

Test: patch the real `_create_environment`, set TERMINAL_DOCKER_NETWORK=false,
and assert the probe's container_config carries docker_network=False.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@teknium1

teknium1 commented Aug 2, 2026

Copy link
Copy Markdown
Contributor

Thanks for the focused fix. The reported omission is present on current main: agent/prompt_builder.py:1074-1089 builds the probe configuration without docker_network, while tools/terminal_tool.py:1602 defaults the omitted value to True and forwards it to Docker at :1625. The added propagation matches the existing sibling paths and the documented terminal.docker_network: false contract.

Automated hermes-sweeper review.

@alt-glitch alt-glitch added type/bug Something isn't working P2 Medium — degraded but workaround exists comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint area/docker Docker image, Compose, packaging backend/docker Docker container execution sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data labels Aug 2, 2026
@teknium1 teknium1 added the sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users label Aug 2, 2026
@GottZ

GottZ commented Aug 3, 2026

Copy link
Copy Markdown

This was generated by AI during triage.

Summary

Four PRs address or underpin this issue: #46358 introduced the Docker network toggle, while #62023, #76911, and #76926 each forward that toggle into the backend-probe container that previously omitted it. Among the direct fixes, #76926 additionally provides the requested behavior-level regression test for the reported propagation failure.

Related pull requests

Duplicates

#62023, #76911, and #76926 implement the same backend-probe propagation fix. #76911 is the untested minimal variant; #62023 adds an AST-based site guard; #76926 adds the behavior-level regression coverage requested by the contributor review.

Suggested consolidation

Keep #76926 open with a salvage path: preserve its one-line propagation fix and behavior-level regression test. Close #76911 as a duplicate of #76926 because the latter addresses its blocking test request, and close #62023 as a duplicate of #76926 despite its maintainer-bot keep_open verdict because #76926 verifies the security-relevant false value through the actual probe factory boundary rather than only checking source structure. Leave #46358 closed as the merged-through-#59149 reference implementation for the underlying toggle.

Complex graph

flowchart LR
    classDef open fill:#dbeafe,stroke:#1d4ed8,color:#1e3a8a
    classDef merged fill:#dcfce7,stroke:#15803d,color:#14532d
    classDef closed fill:#e5e7eb,stroke:#6b7280,color:#1f2937
    classDef unverified fill:#f3f4f6,stroke:#9ca3af,color:#374151
    classDef best stroke-width:3px,stroke:#b45309
    classDef target stroke-width:3px,stroke:#4338ca
    I76906(["issue #76906 (open)"])
    subgraph Dup62023 ["PRs duplicating each other"]
        P62023["PR #62023 (open)"]
        P76911["PR #76911 (open)"]
        P76926["PR #76926 (open)"]
    end
    P76926 -->|best fix| I76906
    class I76906 open
    class P62023 open
    class P76911 open
    class P76926 open
    class P76926 best
    class P76926 target
    click I76906 "https://github.com/NousResearch/hermes-agent/issues/76906"
    click P62023 "https://github.com/NousResearch/hermes-agent/pull/62023"
    click P76911 "https://github.com/NousResearch/hermes-agent/pull/76911"
    click P76926 "https://github.com/NousResearch/hermes-agent/pull/76926"
Loading

Graph: solid arrow = fixes / best fix, dashed arrow = partial or unverified (see edge label); boxed group = PRs duplicating each other; amber border = best fix; indigo border = target; gray node = closed (state tag in the node label).

Cross-PR triage: Reviewed 4 pull requests and 1 issue in this complex. Each diff was read against this issue; Assessment working set: 14 kB of PR diffs, 13 kB of issue/PR text, 5 kB of discussion (5 comments), 5 verify verdicts. verdicts reflect diff content, not PR titles. Part of an automated triage batch.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/docker Docker image, Compose, packaging backend/docker Docker container execution comp/agent Core agent runtime: loop, agent_init, prompt builder, context-compression, responses endpoint P2 Medium — degraded but workaround exists sweeper:blast-contained Sweeper blast radius: contained — one narrow path / opt-in / few users sweeper:risk-security-boundary Sweeper risk: may affect sandboxing, auth, credentials, or sensitive data type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

prompt_builder ignores terminal.docker_network, so the backend-probe container is always networked

4 participants