Skip to content

feat(sandbox): alias/runtime sandbox defaults and persistent network allowlist#2888

Open
dgageot wants to merge 8 commits into
docker:mainfrom
dgageot:board/cb21ab76cf435dac
Open

feat(sandbox): alias/runtime sandbox defaults and persistent network allowlist#2888
dgageot wants to merge 8 commits into
docker:mainfrom
dgageot:board/cb21ab76cf435dac

Conversation

@dgageot
Copy link
Copy Markdown
Member

@dgageot dgageot commented May 23, 2026

This PR makes sandbox enablement configurable from three new sources, and lets users curate a persistent network allowlist for hosts the kit's tool resolver can't infer (custom MCP servers, third-party APIs, registries not covered by aqua, ...).

Sandbox-by-default sources

Three new ways to opt an agent into the sandbox without typing --sandbox:

  • Aliases declared in ~/.config/cagent/config.yaml:

    aliases:
      my-agent:
        ref: ...
        sandbox: true

    Also exposed via docker agent alias add --sandbox.

  • Agent runtime config in the YAML itself:

    runtime:
      sandbox: true

    Per-agent counterpart of the alias flag, useful for catalog agents that always need filesystem or network isolation.

  • An explicit --sandbox=false on the CLI still wins over both, matching the precedence the README and JSON schema already promise. The dispatch logic was previously falling through to the alias / runtime defaults when the user passed --sandbox=false because it only checked !f.sandbox; it now consults cmd.Flags().Changed("sandbox") and the precedence is extracted into a testable resolveSandboxDefault helper.

Network allowlist

Two coordinated additions to widen the default-deny proxy policy without sliding back to the conservative host union the kit falls back to on resolver failure:

  • Author-declared, per agent:

    runtime:
      sandbox: true
      network_allowlist:
        - api.example.com
        - registry.npmjs.org
  • User-managed, persistent for hosts the agent author can't anticipate:

    docker agent sandbox allow <host> [<host>...]
    docker agent sandbox deny <host>
    docker agent sandbox list
    

    Entries land in ~/.config/cagent/config.yaml under sandbox_allowlist and are unioned on every subsequent --sandbox run.

Both lists are unioned with the gateway and the kit-resolved tool install hosts. Commas and embedded whitespace are rejected at write time so a single entry can't smuggle several rules into the policy engine. The launch summary now prints each source on its own line so it's clear which layer punched which hole, and the tool-install summary surfaces a hint pointing at sandbox allow when the per-toolset resolver had to fall back.

Files

agent-schema.json                   |  22 +++
cmd/root/alias.go                   |  15 +-
cmd/root/root.go                    |   1 +
cmd/root/run.go                     |  13 +-
cmd/root/sandbox.go                 | 132 ++++++++++++++++-
cmd/root/sandbox_cmd.go             | 157 +++++++++++++++++++++
cmd/root/sandbox_cmd_test.go        |  52 +++++++
cmd/root/sandbox_test.go            | 127 +++++++++++++++-
docs/configuration/sandbox/index.md |  90 ++++++++++++
docs/features/cli/index.md          |  22 +++
examples/sandbox_agent.yaml         |  18 ++-
pkg/config/latest/types.go          |  26 ++++
pkg/config/resolve_test.go          |  18 +++
pkg/userconfig/userconfig.go        |  69 +++++++++-
pkg/userconfig/userconfig_test.go   |  60 +++++++-

@dgageot dgageot requested a review from a team as a code owner May 23, 2026 08:40
docker-agent

This comment was marked as outdated.

@aheritier aheritier added area/cli CLI commands, flags, output formatting area/config For configuration parsing, YAML, environment variables area/security Authentication, authorization, secrets, vulnerabilities kind/feat PR adds a new feature (maps to feat: commit prefix) labels May 23, 2026
aheritier

This comment was marked as outdated.

Comment thread cmd/root/sandbox.go
Comment thread cmd/root/sandbox.go
Comment thread pkg/config/latest/types.go
Comment thread cmd/root/sandbox.go Outdated
Comment thread cmd/root/sandbox_cmd.go
Comment thread pkg/userconfig/userconfig.go
Comment thread cmd/root/sandbox_cmd.go Outdated
Comment thread cmd/root/sandbox_cmd.go
Comment thread cmd/root/run.go Outdated
@aheritier aheritier self-requested a review May 23, 2026 17:42
@docker-agent

This comment was marked as low quality.

dgageot added 8 commits May 24, 2026 10:33
Aliases declared in ~/.config/cagent/config.yaml can now carry a
sandbox flag. When set, 'docker agent run <alias>' takes the sandbox
path automatically without needing --sandbox on the command line.

The flag joins yolo, model, and hide_tool_results in Alias and is
exposed via 'docker agent alias add --sandbox'. An explicit
--sandbox=false on the command line still wins, matching the
precedence other alias options follow.
Agent authors can now declare a sandbox default in the YAML itself:

  runtime:
    sandbox: true

Any caller of the agent then takes the sandbox path automatically,
without having to remember --sandbox. An explicit --sandbox=false on
the CLI still wins, matching the precedence aliases follow.

This is the per-agent counterpart of the per-alias sandbox flag, and
is especially useful for catalog agents that always need filesystem
or network isolation.

Adds the new RuntimeDefaults block to the latest config schema, the
matching JSON schema definition, and a refreshed sandbox_agent.yaml
example demonstrating the feature.
Agents that talk to endpoints the auto-installer can't infer (custom
MCP servers, third-party APIs, registries not covered by the aqua
resolver, ...) saw a default-deny 403 from the sandbox proxy on
first contact, then had to fall back to the wider conservative host
union the kit uses on resolution failures.

Let agent authors declare those hosts explicitly:

  runtime:
    sandbox: true
    network_allowlist:
      - api.example.com
      - registry.npmjs.org

The list is unioned with the gateway and tool-install hosts the
runner already opens automatically and printed before launch so
users can audit exactly which holes the run punched in the
default-deny policy. Commas and whitespace are rejected so a single
entry can't smuggle several rules into the policy engine.
Hosts the kit's per-toolset resolver can't infer (custom MCP
endpoints, third-party APIs, registries not covered by aqua) showed
up as a 403 from the sandbox proxy and forced the run to fall back
to the wider conservative host union. Authors can now declare them
in runtime.network_allowlist, but users running someone else's agent
still had no easy fix.

Add a persistent user-level allowlist plus three subcommands to
manage it:

  docker agent sandbox allow <host> [<host>...]
  docker agent sandbox deny <host>
  docker agent sandbox list

Entries land in ~/.config/cagent/config.yaml under sandbox_allowlist
and are unioned with the gateway, the kit-resolved tool install
hosts, and the agent-declared list on every subsequent --sandbox
run. The launch summary now prints each source on its own line so
it's clear which layer punched which hole, and the tool-install
summary surfaces a hint pointing at 'sandbox allow' when the
per-toolset resolver had to fall back.

Commas and embedded whitespace are rejected at write time so a
single entry can't smuggle several rules into the policy engine.
…aults

The dispatch logic only checked !f.sandbox before consulting the
alias and the agent's runtime.sandbox, so passing --sandbox=false
on the CLI silently fell through to either of the lower-priority
sources. The README and the schema both promise that the explicit
flag wins, so detect whether the user actually set it via
cmd.Flags().Changed and skip the override path in that case.

Extract the precedence into resolveSandboxDefault so the rule is
testable on its own, and add a regression test covering both the
"flag not set" and "flag explicitly false" paths.
Threads the *latestcfg.Config loaded by resolveSandboxDefault through
to runInSandbox so agentNetworkAllowlist no longer re-resolves and
re-loads the same agent ref. For OCI-hosted agents this drops one
network round-trip per sandboxed run.

agentNetworkAllowlist now also drops entries with embedded commas or
whitespace and warns: an agent YAML with 'a.example.com, b.example.com'
as a single string used to feed a malformed value straight into the
proxy policy, where the comma silently smuggled two rules into one.

Narrows resolveSandboxDefault to take agentRef string instead of
[]string, dropping the implicit args[0] contract from the call site,
and refreshes the misleading runOrExec comment on alias.Sandbox so it
describes the post-decision state, not the side-effect.
Previously a batch like ('valid.example.com', 'bad,host.example.com')
appended the valid entry to SandboxAllowlist before bailing out on the
malformed one, leaving the in-memory *Config inconsistent with what
would have been persisted to disk. Validate every entry first, mutate
only when the whole batch is clean.
'sandbox deny <host>' used to error when the host was already absent,
which is unusual for remove-style CLIs (docker rm --force, git branch
-D, ...) and surprises scripts that don't pre-check membership. Now
prints a notice and returns nil so 'deny' is safe to retry.

Also strips user-supplied hostnames from the telemetry payload for
allow / deny / list. Sandbox hosts often identify private corp
endpoints (internal registries, VPN-only APIs); we still record the
sub-command, but no longer the values.
@dgageot dgageot force-pushed the board/cb21ab76cf435dac branch from 1f4dbcc to c8ef1af Compare May 24, 2026 08:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/cli CLI commands, flags, output formatting area/config For configuration parsing, YAML, environment variables area/security Authentication, authorization, secrets, vulnerabilities kind/feat PR adds a new feature (maps to feat: commit prefix)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants