fix(agent): probe container honors docker_network egress control (#76906) - #76926
fix(agent): probe container honors docker_network egress control (#76906)#76926a-yeyang wants to merge 1 commit into
Conversation
…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>
|
Thanks for the focused fix. The reported omission is present on current main: Automated hermes-sweeper review. |
SummaryFour 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 consolidationKeep #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 graphflowchart 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"
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. |
What does this PR do?
_probe_remote_backend()inagent/prompt_builder.pyruns a tiny introspection command inside the configured terminal backend to describe it in the system prompt. For container backends it assembles its owncontainer_configdict — but it omitsdocker_network. That key then falls through to theTruedefault in_create_environment, so theprompt-backend-probecontainer comes up onbridgeeven when the operator has setdocker_network: false/TERMINAL_DOCKER_NETWORK=falseas an egress control.The agent's own shell container is air-gapped correctly (the live terminal path in
tools/terminal_tool.pypassesdocker_network); this second probe container is not, and it inherits the samedocker_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'scontainer_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
(Bounded today —
_resolve_container_task_idcollapses everything todefaultand the probe runs a fixedprintf/unamewith 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'scontainer_config, mirroringtools/terminal_tool.py.tests/agent/test_prompt_builder.py—test_probe_remote_backend_honors_docker_network_false: withTERMINAL_DOCKER_NETWORK=false, patch the real_create_environmentand assert the probe'scontainer_configcarriesdocker_network=False.How to Test
docker_network: false(orTERMINAL_DOCKER_NETWORK=false) and adocker_volumesmount.docker psshows two containers;docker inspect <probe> --format '{{.HostConfig.NetworkMode}}'isbridge(default). After: the probe container'sNetworkModeisnone, matching the agent shell.Automated:
I confirmed the new test fails on
main(probecontainer_confighas nodocker_network) and passes with this change. Fulltests/agent/test_prompt_builder.py: 56 passed, 1 skipped.Checklist
Code
fix(agent):)docker_network)Documentation & Housekeeping
docker_networkalready documented, this makes the probe honor it)cli-config.yaml.example— N/A (no new/changed keys)CONTRIBUTING.md/AGENTS.md— N/A