fix(gateway): translate Docker container paths for media delivery - #42305
fix(gateway): translate Docker container paths for media delivery#42305liuhao1024 wants to merge 1 commit into
Conversation
When terminal.backend is docker, the agent produces files inside the sandbox and references them by container path (e.g. /output/report.pdf). The gateway runs on the host and validate_media_delivery_path() resolves paths against the host filesystem, so container paths are always rejected. Add _translate_docker_container_path() which maps container paths to host paths using longest-prefix match against terminal.docker_volumes config entries (host:container format). Translation runs before resolve(), and all existing validation (denylist, strict mode, recency) still applies after translation. Fixes NousResearch#42299
teknium1
left a comment
There was a problem hiding this comment.
Thanks for targeting the host/container boundary; the premise is still present on current main: gateway/platforms/base.py:1302-1305 resolves MEDIA paths only on the host and rejects an unresolved container path.
Problems
- Security:
gateway/platforms/base.py:1074-1075joins an unnormalized suffix onto the host mount with no containment check. With/host/export:/output,MEDIA:/output/../../home/user/fileresolves outside/host/export. In default mode, current validation accepts existing paths that are not denylisted (gateway/platforms/base.py:1320-1330), so this can bypass the intended bind-mount boundary. - Docker syntax:
gateway/platforms/base.py:1060usesrpartition(':'), so a documented mount such as/host/data:/data:rois parsed withroas its container prefix. The documented syntax explicitly supportshost_path:container_path[:options](website/docs/user-guide/configuration.md:426-434).
Suggested changes
- Resolve both the translated file and mapped host root, then require containment within that root; add a traversal regression test.
- Parse optional Docker mount modes correctly and test a
:romount.
Automated hermes-sweeper review.
| for vol in volumes: | ||
| if not isinstance(vol, str) or ":" not in vol: | ||
| continue | ||
| host_part, _, container_part = vol.rpartition(":") |
There was a problem hiding this comment.
This misparses supported host:container[:options] specs: /host/data:/data:ro produces container_part == "ro", so paths below /data never translate. Please parse the optional mode separately and add a :ro regression test.
| return None | ||
|
|
||
| suffix = candidate[best_match_len:] | ||
| return best_host_prefix + suffix |
There was a problem hiding this comment.
The suffix is unnormalized, so /output/../../home/user/file under /host/export:/output becomes /host/export/../../home/user/file and can resolve outside the configured bind mount. Resolve the host root and candidate and reject results not contained in that root before returning them.
|
Closing as resolved by #81746 (merge commit 238351a), which merged the same container→host mount translation approach salvaged from #37207 — with #27779 by @LEAFERx as the first submission for this bug. Your PR independently arrived at the same fix; credit to all four contributors in the cluster. Thanks! |
What does this PR do?
Adds Docker container-to-host path translation in
validate_media_delivery_path()so that media delivery works when the agent runs in a Docker sandbox with configured volume mounts.Related Issue
Fixes #42299
Type of Change
Changes Made
gateway/platforms/base.py: Added_translate_docker_container_path()helper that maps container paths (e.g./output/report.pdf) to host paths using longest-prefix match againstterminal.docker_volumesconfig entries. Translation runs beforeresolve()so the host file can be found; all existing validation (denylist, strict mode, recency window) applies unchanged after translation.tests/gateway/test_platform_base.py: AddedTestDockerContainerPathTranslationclass with 11 tests covering: basic translation, nested paths, longest-prefix match, non-docker backend, no matching volume, empty volumes, config errors, exact mount point match, integration withvalidate_media_delivery_path, and denylist enforcement after translation.How to Test
terminal.backend: dockerwithdocker_volumes: ["/host/path:/output"]/output/report.pdfMEDIA:/output/report.pdfpytest tests/gateway/test_platform_base.py::TestDockerContainerPathTranslation -vChecklist
Code
fix(scope):,feat(scope):, etc.)pytest tests/ -qand all tests passDocumentation & Housekeeping
docs/, docstrings) — or N/Acli-config.yaml.exampleif I added/changed config keys — or N/ACONTRIBUTING.mdorAGENTS.mdif I changed architecture or workflows — or N/ACode Intelligence
validate_media_delivery_path()(module-level function, called byBasePlatformAdapterclass method + gateway adapters)terminal.backend == dockertelegram.py::_missing_media_path_error()already had a hint about container paths; this fix resolves the underlying validation gap