-
Notifications
You must be signed in to change notification settings - Fork 22
container_shell: isolated network by default, plus optional network transport #93
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
0ead3e8
5e201ec
065b75b
900131e
ea8cc12
3e6d64b
afa2a3c
e4a1d71
adab2d4
11ab054
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,13 @@ | ||
| # Container Shell Taskflows | ||
|
|
||
| Runs arbitrary CLI commands inside an isolated Docker container. One container | ||
| per MCP server process — started on the first `shell_exec` call, stopped on | ||
| per MCP server process — started on the first `container_shell_exec` call, stopped on | ||
| exit. An optional host directory is mounted at `/workspace` inside the container. | ||
|
|
||
|
Comment on lines
3
to
6
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 11ab054. Added a note in the README intro that the container is egress-locked by default ( |
||
| By default the container is egress-locked: it runs with `--network none`, so | ||
| outbound access (`curl`, `wget`, `git` remote operations) is disabled until a | ||
| toolbox opts in by setting `CONTAINER_NETWORK` (for example `bridge`). | ||
|
|
||
| Four container profiles are provided. Each has its own Dockerfile, toolbox | ||
| YAML, and demo taskflow. | ||
|
|
||
|
|
@@ -117,17 +121,17 @@ taskflow: | |
| Analyse the binary at /workspace/target.elf using static analysis only. | ||
| ``` | ||
|
|
||
| `shell_exec` requires user confirmation by default (`confirm: [shell_exec]` in | ||
| `container_shell_exec` requires user confirmation by default (`confirm: [container_shell_exec]` in | ||
| all toolbox YAMLs). Pass `headless: true` at the task level to skip | ||
| confirmation in automated pipelines. | ||
|
|
||
| ## Notes | ||
|
|
||
| - The container is shared across all `shell_exec` calls within a single | ||
| - The container is shared across all `container_shell_exec` calls within a single | ||
| taskflow run. State (files written, processes started) persists between calls. | ||
| - `--rm` is set on `docker run`, so the container is removed automatically when | ||
| stopped. | ||
| - The container name follows the pattern `seclab-shell-<8 hex chars>` and is | ||
| visible in `docker ps`. | ||
| - If `docker run` fails (e.g. image not found), `shell_exec` returns an error | ||
| - If `docker run` fails (e.g. image not found), `container_shell_exec` returns an error | ||
| string rather than raising, so the agent can report the problem cleanly. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,14 +15,15 @@ server_params: | |
| CONTAINER_TIMEOUT: "{{ env('CONTAINER_TIMEOUT', '30') }}" | ||
| CONTAINER_PERSIST: "{{ env('CONTAINER_PERSIST', required=False) }}" | ||
| CONTAINER_PERSIST_KEY: "{{ env('CONTAINER_PERSIST_KEY', required=False) }}" | ||
| CONTAINER_NETWORK: "{{ env('CONTAINER_NETWORK', required=False) }}" | ||
| LOG_DIR: "{{ env('LOG_DIR') }}" | ||
|
|
||
| confirm: | ||
| - shell_exec | ||
| - container_shell_exec | ||
|
|
||
| server_prompt: | | ||
| ## Container Shell (base) | ||
| You have access to an isolated Docker container. Use `shell_exec` to run commands. | ||
| You have access to an isolated Docker container. Use `container_shell_exec` to run commands. | ||
| The working directory is /workspace (mapped from the host workspace if configured). | ||
|
|
||
|
Comment on lines
+26
to
28
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 11ab054. Added a note to the base toolbox prompt that networking is disabled by default ( |
||
| Available tools in this container: | ||
|
|
@@ -37,4 +38,8 @@ server_prompt: | | |
| - curl / wget — HTTP requests | ||
| - git — version control | ||
|
|
||
| Networking is disabled by default: the container runs with `--network none`, | ||
| so `curl`, `wget`, and `git` remote operations fail unless this toolbox opts | ||
| in by setting `CONTAINER_NETWORK` (for example `bridge`). | ||
|
|
||
| All commands run inside the container. Output includes stdout, stderr, and exit code. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| # SPDX-FileCopyrightText: GitHub, Inc. | ||
| # SPDX-License-Identifier: MIT | ||
|
|
||
| seclab-taskflow-agent: | ||
| filetype: toolbox | ||
| version: "1.0" | ||
|
|
||
| # Remote variant of the container shell. Instead of launching container_shell | ||
| # as a local stdio subprocess (which needs a Docker socket in the agent | ||
| # environment), this connects to a container_shell MCP server that is already | ||
| # running elsewhere over Streamable HTTP. The server owns the Docker daemon; the | ||
| # agent only speaks MCP to it. This is what lets an AWF-isolated agent use | ||
| # containerized shell execution without ever being handed a Docker socket: the | ||
| # server runs outside the sandbox and is reached over a single allowlisted host | ||
| # service port. | ||
| # | ||
| # CONTAINER_SHELL_URL must point at the running server's Streamable HTTP | ||
| # endpoint, for example http://host.docker.internal:8765/mcp/. | ||
| server_params: | ||
| kind: streamable | ||
| url: "{{ env('CONTAINER_SHELL_URL') }}" | ||
|
|
||
| confirm: | ||
| - container_shell_exec | ||
|
|
||
|
Comment on lines
+19
to
+25
|
||
| server_prompt: | | ||
| ## Container Shell (remote) | ||
| You have access to an isolated Docker container running on a remote shell | ||
| server. Use `container_shell_exec` to run commands inside it. The working | ||
| directory is /workspace (mapped from the host workspace if configured). | ||
|
|
||
|
Comment on lines
+28
to
+31
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed in 11ab054. Clarified in the remote toolbox prompt that outbound networking may be disabled by default and is controlled server-side by the remote server |
||
| Available tools in this container: | ||
| - bash, coreutils (ls, cat, grep, find, sed, awk, sort, uniq, wc, ...) | ||
| - file: identify file type by magic bytes | ||
| - strings: extract printable strings from binary files | ||
| - objdump: disassemble and dump object/binary files | ||
| - readelf: display ELF binary structure | ||
| - nm: list symbols from object files | ||
| - xxd / hexdump: hex inspection | ||
| - python3: scripting | ||
| - curl / wget: HTTP requests | ||
| - git: version control | ||
|
|
||
| Outbound networking may be disabled by default: egress is controlled by the | ||
| remote server's `CONTAINER_NETWORK` setting, so `curl`, `wget`, and `git` | ||
| remote operations only work when the server has networking enabled. | ||
|
|
||
| All commands run inside the container. Output includes stdout, stderr, and exit code. | ||
Uh oh!
There was an error while loading. Please reload this page.