{"slug": "running-ai-agents-in-github-actions-with-docker-sandboxes", "title": "Running AI agents in GitHub Actions with Docker Sandboxes", "summary": "GitHub Agentic Workflows (gh-aw) version 0.82.9 added Docker Sandboxes as a supported agent runtime, allowing AI coding agents in GitHub Actions to run Docker containers and execute arbitrary commands within an isolated microVM. The integration, which shipped in July 2026, enables agents to perform tasks like running integration tests with Testcontainers and opening draft pull requests, with network policy and secrets injection for isolation.", "body_md": "In July 2026, [GitHub Agentic Workflows](https://github.com/github/gh-aw) added [Docker Sandboxes as a supported agent runtime](https://github.github.com/gh-aw/reference/agent-runtimes/#docker-sbx). It means that in your CI an AI coding agent can have broad control of its environment, including being able to run Docker containers, while the environment itself is isolated in a microVM with a network policy and secrets injection like the current best practices for AI isolation advice.\n\nAgentic isolation matters because useful coding agents do more than read a repository and suggest a patch. They install tools, run arbitrary shell commands, execute project code, start databases, and occasionally discover surprising new meanings for the word “cleanup.” Those capabilities make the agent useful, and direct access to a CI runner gives every mistake a larger blast radius.\n\nNow, with sbx integrated, the boundary for the Agent is a disposable environment with substantial freedom inside and narrow access to everything outside it.\n\nI put together a [small example](https://github.com/shelajev/docker-sandbox-gh-aw-demo) to see what that looks like in practice. The agent runs on a GitHub-hosted Ubuntu runner, enters a Docker Sandbox (sbx), runs a Java integration test suite with PostgreSQL using Testcontainers, finds an intentionally seeded bug, fixes it, and opens a draft pull request. The Github Agentic Workflows offers the integration out-of-the-box, so the setup requires zero custom configuration for actions.\n\n## What are GitHub Agentic Workflows?\n\n[GitHub Actions](https://docs.github.com/actions) remains the CI system. It schedules the job, provides the Ubuntu runner, manages permissions and secrets, and records the result.\n\nGitHub Agentic Workflows, usually shortened to `gh-aw`\n\n, is an open-source GitHub CLI extension and compiler. You describe an agentic workflow in a Markdown file that combines execution configuration in YAML frontmatter with the agent’s task in the body. Running `gh aw compile`\n\nturns that source into a conventional GitHub Actions workflow with a `.lock.yml`\n\nsuffix.\n\nThe relationship looks like this:\n\n```\nMarkdown workflow\n    |\n    | gh aw compile\n    v\nGenerated GitHub Actions .lock.yml\n    |\n    | runs on ubuntu-24.04\n    v\nDocker Sandbox microVM\n    |\n    v\nCopilot agent and its tools\n```\n\n`docker-sbx`\n\nbelongs to `gh-aw`\n\n‘s agent runtime configuration. The `runs-on`\n\nfield still selects `ubuntu-24.04`\n\n, and the compiled file is a standard GitHub Actions workflow. It installs the sandbox tooling, authenticates it, checks the runner, starts the agent in the sandbox, and cleans everything up afterward.\n\nThat integration [landed in gh-aw](https://github.com/github/gh-aw/pull/45006) and shipped in version 0.82.9.\n\n## Configuring sbx in GitHub Actions\n\nHere is the configuration from the sample’s [sandbox-explorer.md](https://github.com/shelajev/docker-sandbox-gh-aw-demo/blob/main/.github/workflows/sandbox-explorer.md):\n\n```\n---\nname: \"Docker Sandboxes sample: exploratory test\"\n\non:\n  workflow_dispatch:\n\nruns-on: ubuntu-24.04\n\npermissions:\n  contents: read\n  copilot-requests: write\n\nengine: copilot\n\nnetwork:\n  allowed:\n    - defaults\n    - github\n    - containers\n    - java\n\nsandbox:\n  agent:\n    id: awf\n    runtime: docker-sbx\n    sudo: true\n\ntools:\n  edit:\n  bash: [\":*\"]\n\nsafe-outputs:\n  create-pull-request:\n    title-prefix: \"[docker-sbx sample] \"\n    draft: true\n    protected-files: blocked\n    allowed-files:\n      - \"src/**\"\n---\n```\n\nThe three lines under `sandbox.agent`\n\nselect the Docker Sandbox runtime. Inside it, the agent has the `sudo`\n\nand unrestricted shell access needed to build the application and start its test infrastructure.\n\nOutside the sandbox, the workflow keeps a much smaller surface. Its `network`\n\nblock allowlists the destinations this job needs, while the agent’s GitHub token can read repository contents and send requests to Copilot. Pull request creation happens in a separate safe-output job whose patch may contain files only under `src/**`\n\n.\n\nHow much autonomy a CI agent should receive depends on the job. For this one, the split is useful: broad shell access inside the sandbox, small network and repository surfaces outside it, and a draft PR that still expects human review.\n\n## The isolation boundary is a micro VM\n\nWhile it’s common to assume that “Docker” implies a single application container, this setup actually uses a microVM as the primary isolation boundary.\n\nWith [sbx](https://docs.docker.com/ai/sandboxes/architecture/), every sandbox is a dedicated environment with its own kernel, filesystem, and network stack. Most importantly, it runs its own private Docker daemon. This means the agent gets full root privileges inside the VM without ever gaining control over the host’s Docker daemon. The only bridge between them is the explicit shared workspace of the repository.\n\nHaving a private daemon is a game-changer for integration testing. In this demo, the app runs Testcontainers exactly as a developer would on their local machine. The resulting structure looks like this:\n\n```\nGitHub Actions runner\n└── Docker Sandbox microVM\n    ├── GitHub Agentic Workflows agent\n    └── Private Docker daemon\n        ├── Maven / Java 21 container\n        └── PostgreSQL Testcontainers container\n```\n\nTo keep the environment clean, the test launcher runs Maven inside a pinned container, passing the sandbox’s Docker socket through so it can talk to the private daemon:\n\n```\ndocker run --rm \\\n  --add-host=host.testcontainers.internal:host-gateway \\\n  -e TESTCONTAINERS_HOST_OVERRIDE=host.testcontainers.internal \\\n  -v \"$PWD:/workspace\" \\\n  -w /workspace \\\n  -v /var/run/docker.sock:/var/run/docker.sock \\\n  maven:3.9.9-eclipse-temurin-21@sha256:3a4ab3276a087bf276f79cae96b1af04f53731bec53fb2e651aca79e4b10211e \\\n  mvn --batch-mode \"$@\" test\n```\n\nTestcontainers then uses that socket to spin up the PostgreSQL database. It sounds like a lot of layers—a container running a build that starts another container, all inside a microVM on a CI runner but each layer serves a specific purpose in ensuring the agent remains isolated yet fully capable.\n\n## Giving the agent a defect worth finding\n\nThe sample is a small Java 21 registration service. Its requirements say that email addresses are case-insensitive. The seeded implementation stores them as provided and relies on PostgreSQL’s case-sensitive unique constraint. An existing Testcontainers integration test catches exact duplicates but says nothing about the latter case.\n\nThe Markdown portion of the workflow asks the agent to inspect the requirement and code, run the baseline suite, and add a test for two addresses that differ only in case. If the invariant fails, the agent should make the smallest source correction. Before touching the application, it records `uname`\n\n, Docker version, Docker information, and a tiny Alpine container run, leaving specific evidence in the workflow log about where the work executed.\n\nThe task itself is plain Markdown beneath the frontmatter in the yaml file. The important part for us (after some commands for recording the environment for debugging) is:\n\n```\nAct as a bounded exploratory tester for this repository.\n... \n\nThen:\n1. Read `REQUIREMENTS.md` and the relevant source and test files.\n2. Run `./scripts/test-in-docker.sh` without changing anything.\n3. Add a PostgreSQL Testcontainers test that checks registration of two\n   addresses that differ only in letter case.\n4. Run the focused test and explain the observed behavior.\n5. If the implementation violates the documented invariant, make the\n   smallest fix under `src/`.\n6. Run the complete test suite again.\n7. Create one draft pull request containing the regression test and fix.\n```\n\nAnd the prompt level guardrails to suggest the correct behavior:\n\n```\nDo not modify dependency manifests, workflow files, scripts, documentation,\nor generated files. Do not weaken or delete existing tests. Include the\ncommands run and their results in the pull request description.\n```\n\nThe real run of course followed that path: its baseline passed, then the new case-variation test failed with:\n\n```\nexpected: &lt;false&gt; but was: &lt;true&gt;\n```\n\nThe agent normalized the email before inserting it, reran the complete suite, and got two passing integration tests.\n\nThe log reported Docker client and server version 29.7.1 with the `default`\n\ncontext. It is the correct Docker version currently in the sbx default sandbox template. This is the sandbox’s private daemon, the one Testcontainers library used to launch PostgreSQL for the integration tests.\n\n*The complete workflow passed on GitHub’s hosted ubuntu-24.04 runner. The *\n\n*run**took 11 minutes and 16 seconds.*\n\nThe safe-output job then opened a draft PR containing exactly two files under `src/**`\n\n: the regression test and the one-line normalization fix. Workflow configuration, scripts, dependencies, and documentation were outside its allowed patch surface.\n\n*The generated **draft pull request** stayed inside the declared source-only boundary.*\n\n## Running the workflow yourself\n\nStart by installing the `gh-aw`\n\n:\n\n```\ngh extension install github/gh-aw\n```\n\nThe compiled Docker Sandbox runtime needs Docker credentials to authenticate and pull its sandbox template. Add `DOCKER_USERNAME`\n\nand `DOCKER_PAT`\n\nunder the sample repository’s **Settings > Secrets and variables > Actions**, or let the GitHub CLI prompt for both values:\n\n```\ngh secret set DOCKER_USERNAME\ngh secret set DOCKER_PAT\n```\n\nThe repository’s Copilot entitlement and `copilot-requests: write`\n\nwere sufficient for the successful sample. Repositories without that entitlement can use a supported `COPILOT_GITHUB_TOKEN`\n\nsecret as documented by `gh-aw`\n\n.\n\nAlso enable **Allow GitHub Actions to create and approve pull requests** in the repository’s Actions settings. Then compile the Markdown source and commit both the source and generated workflow:\n\n```\ngh aw compile sandbox-explorer\n\ngit add .github/workflows/sandbox-explorer.md \\\n  .github/workflows/sandbox-explorer.lock.yml\ngit commit -m \"Compile Docker Sandboxes sample workflow\"\ngit push\n```\n\nThe `.lock.yml`\n\nis generated code. Changes belong in the Markdown source, followed by another compile.\n\nFinally, start the workflow and watch it:\n\n```\ngh aw run sandbox-explorer\ngh run watch\n```\n\nThe sample works on GitHub’s hosted `ubuntu-24.04`\n\nrunner as committed. A self-hosted Linux runner needs an appropriate KVM-capable setup, plus the Docker and system access required by Docker Sandboxes.\n\n## Try sbx on your laptop\n\nSupport for isolating your agents in CI is fantastic, but the easiest way to understand Docker Sandboxes is to put one around an agent on a local project. Follow the [Docker Sandboxes setup](https://docs.docker.com/ai/sandboxes/) for your platform, sign in, move to a repository, and run an installed agent:\n\n```\nsbx login\ncd ~/my-project\n\nsbx run <claude|codex|opencode>\n```\n\nGive it a task that needs real tools, such as running tests, building an image, or starting a Testcontainers dependency. `sbx`\n\nis much easier to evaluate and understand when the workload is your actual development loop.\n\nAnd if your experiment grows into an organization-wide agent rollout, [Docker AI Governance](https://www.docker.com/products/ai-governance/) is the next thing to explore. It applies organization and team policies for sandbox network, filesystem, and MCP access, and records policy decisions in audit logs. Those records help to identify the source client, including `sbx`\n\n, and the machine hostname, so the same policy and audit model can easily cover your team’s laptops and your CI runners.", "url": "https://wpnews.pro/news/running-ai-agents-in-github-actions-with-docker-sandboxes", "canonical_source": "https://www.docker.com/blog/running-ai-agents-in-github-actions-with-docker-sandboxes/", "published_at": "2026-08-21 13:00:00+00:00", "updated_at": "2026-08-21 13:14:18.524573+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "ai-infrastructure", "ai-safety"], "entities": ["GitHub", "GitHub Agentic Workflows", "Docker Sandboxes", "gh-aw", "GitHub Actions", "Copilot", "Testcontainers", "PostgreSQL"], "alternates": {"html": "https://wpnews.pro/news/running-ai-agents-in-github-actions-with-docker-sandboxes", "markdown": "https://wpnews.pro/news/running-ai-agents-in-github-actions-with-docker-sandboxes.md", "text": "https://wpnews.pro/news/running-ai-agents-in-github-actions-with-docker-sandboxes.txt", "jsonld": "https://wpnews.pro/news/running-ai-agents-in-github-actions-with-docker-sandboxes.jsonld"}}