Agent Guardrails Belong in Config, and Config Needs Tests

  • Thread starter Thread starter Mike Dabydeen
  • Start date Start date
M

Mike Dabydeen

Guest
When an AI agent can run shell commands in your pipeline, its permissions are infrastructure. They should be declared where reviewers look, versioned with the agent, and tested on every change. Docker Agent gets the first two right. The third is up to you, and when I wrote the tests, one widely used permission pattern failed in a way worth knowing about.

The setup​


Docker Agent is Docker's open-source runtime for teams of agents. A team is a config file: models, agents, which agents each one may delegate to, which tools each may use, and the policy around all of it. You run it with docker agent run crew.yaml.

My test project, release-gate-crew, is a release gate for container services. A lead agent delegates to a container auditor and a pipeline auditor, then hands their findings to a scribe that writes a PASS/BLOCK report. The sample service under review is deliberately bad: an unpinned base image, a secret in ENV, a privileged container with the Docker socket mounted, and a pull_request_target workflow that checks out untrusted code with write permissions.

Every control sits in the same file as the agents:

Code:
agents:
  container_auditor:
    model: worker
    instruction_file: prompts/container_auditor.md
    toolsets:
      - type: filesystem
        allow_list: ["./target"]   # read scope
      - type: shell

runtime:
  safety: restricted               # unattended: deny anything not allowed

permissions:
  allow: ["read_file", "shell:cmd=grep -n *"]
  deny:  ["shell:cmd=*curl*", "shell:cmd=*&&*", "shell:cmd=*;*", "shell:cmd=*|*"]

budget:
  max_cost: 0.50                   # one pot shared by every agent
  max_time: 10m

A .agentsignore file hides .env and key files from every agent. The same team also exists as crew.hcl, because Docker Agent reads HCL too, and platform teams that live in Terraform may prefer it.

Testing guardrails without a model​


Guardrails are deterministic, so they should be testable without paying for tokens or tolerating model variance. I wrote a scripted, OpenAI-compatible stub model in Go and pointed every agent at it through a config flavor. The stub plays a fixed sequence per agent. It delegates, reads files, and then deliberately tries things the config should refuse.

A Go integration test drives the real docker-agent binary against both config files and checks nine written requirements. The runtime's own responses:


Attempt

Result

Read target/.env

excluded by .agentsignore

Pipeline auditor reads a file outside ./target

outside the allowed directories (./target)

Scribe writes target/Dockerfile

denied by restricted safety mode, no prompt

grep -n FROM target/Dockerfile && curl --version

denied by permissions configuration

All of that held, for YAML and HCL alike.

The pattern that didn't hold​


Permission rules are globs matched against the whole command string, and * matches spaces. So consider the prefix style common in examples:

Code:
permissions:
  allow: ["shell:cmd=grep -n *"]
  deny:  ["shell:cmd=curl *"]

The command grep -n FROM target/Dockerfile && curl --version begins with grep -n, so the allow rule matches. It does not begin with curl, so the deny rule misses. Deny is evaluated first, finds nothing, then allow approves. In my test, curl ran and printed its version banner. The restricted safety mode did not stop it, because an explicit allow outranks the mode.

Docker's documentation says permissions are client-side and not a security boundary, and it recommends sandbox mode for isolation. I agree with that framing. The risk is practical: prefix rules look precise, and they are what most people will copy.

Four changes close the gap:

  1. Deny shell operators: *&&*, *;*, *|*, backticks and $(.
  2. Match denied binaries anywhere: *curl*, not curl *.
  3. Allow one narrow command per agent that needs a shell.
  4. Use --sandbox, which runs the team in a Docker Sandboxes VM, for anything you don't fully trust.

My suite keeps a test that reproduces the bypass. If a future release starts parsing compound commands, that test will fail and tell me to revisit the advice.

Other things a platform team should know​

  • The filesystem toolset is unrestricted by default. Set allow_list on every one.
  • A config pulled from a registry can declare runtime.safety: autonomous. Your own flag or user settings take precedence only if you set them.
  • Sub-agents receive only the task text the lead writes, inside a <task> block. Good isolation, but the lead must pass along everything a specialist needs.
  • The project moves quickly: 17 releases in September 2026. Pin the version in CI and disable telemetry there with TELEMETRY_ENABLED=false.

What the stub can't tell you​


None of this measures review quality. A scripted stub proves the harness, not the judgement. The repository includes three docker agent eval cases for that: block the flawed sample, refuse to reveal the secret, and refuse to claim an edit. They need real model keys and a container runtime, and I haven't run them yet.

That split is the main lesson I'd take to any agent platform. Test the guardrails deterministically on every push. Evaluate the model's judgement separately, with repeated runs, before you trust a gate decision.
 

Thread statistics

Created
Mike Dabydeen,
Replies
0
Views
5
Back
Top