Docker Sandboxes mixin adding the Dagger CLI + engine to run containerized CI/CD pipelines
299
sha256:71bf7fd0b77d…
32 Bytes
2 months ago
A standalone Docker Sandboxes kit (kind: mixin) that adds
Dagger — a programmable, containerized CI/CD engine to any sandbox agent.
This kit gives whatever agent you run the ability to define and execute real build/test/ship pipelines with Dagger Functions, the Dagger Shell, and the GraphQL API. Because a Docker Sandbox is a microVM with its own private Docker daemon, the Dagger engine provisions and runs entirely inside the sandbox, no host access, and no remote runner to configure.
Three observable things, so each is independently verifiable (see §3):
v0.21.7 as the agent user (1000) into ~/.local/bin.dl.dagger.io), the engine image
registry (registry.dagger.io + ghcr.io mirror), and Docker Hub (registry-1.docker.io, …)
so pipelines can pull common public images.agentContext note so the agent knows the capability exists and how to call it
(dagger -c, dagger call, dagger query).Dagger Cloud (trace visualization) is optional and off by default — see Dagger Cloud (optional).
Layer the mixin onto an agent. From the published image:
sbx run --kit docker.io/ajeetraina777/sbx-kits-dagger:latest claude
Or straight from this repo over git:
sbx run --kit "git+https://github.com/ajeetraina/sbx-kits-dagger.git#dir=kit" claude
Or from a local clone (the kit spec lives in the kit/ subdirectory, kept separate from
the repo's docs, scripts, and .git/ so nothing but the spec is packed):
git clone https://github.com/ajeetraina/sbx-kits-dagger.git
sbx run --kit ./sbx-kits-dagger/kit/ claude
The trailing argument (claude above) is the coding agent that runs inside the sandbox, a
separate axis from the kit. Any supported agent works — sbx run --help lists them:
claude, claude-bedrock, codex, copilot, cursor, docker-agent, droid, gemini, kiro, opencode, shell
So you can swap claude for, say, codex:
sbx run --kit docker.io/ajeetraina777/sbx-kits-dagger:latest codex
Arguments meant for the agent itself go after a -- separator, e.g.
sbx run --kit ...:latest codex -- --help.
Once you're in the sandbox session, use ! shell escapes to prove the mixin is really inside.
Verify on independent layers, from a cheap version check up to a full end-to-end pipeline run.
i. The CLI is installed (the pinned version, on PATH as user 1000):
!command -v dagger && dagger version
Expect dagger to resolve under ~/.local/bin/ and the version to report v0.21.7 — the exact
pin from this kit's spec.yaml, installed to the user-site location that matches the kit installing
as user 1000 rather than as root.
ii. The runtime precondition holds — this sandbox has a working Docker daemon. Dagger provisions its engine as a container on the sandbox's private daemon, so the engine can only start if a daemon is reachable. This is the check that proves the biggest requirement is satisfied in this sandbox (it replaces the credential check other kits do, since this kit has none):
!docker version
Expect both a Client and a Server section — the Server confirms a live daemon inside the VM.
iii. End-to-end functional proof — run a pipeline that forces engine provisioning and a real container exec. This single command transitively exercises the CLI, engine provisioning on the private daemon, an image pull over the network allowlist, and container execution — so if you only run one check, run this one:
!dagger -c 'container | from alpine | with-exec echo,"dagger works in a docker sandbox" | stdout'
Expect dagger works in a docker sandbox printed after the engine image pulls (the first run
downloads the engine image and can take up to a minute; subsequent runs are fast because the engine
stays warm and results are cached).
A second, GraphQL-based proof of the same path:
!dagger query <<'EOF'
{ container { from(address:"alpine") { withExec(args:["uname","-a"]) { stdout } } } }
EOF
The agentContext note tells the agent it can do this; the one-liners:
# Dagger Shell — typed pipes, no module needed
dagger -c 'container | from alpine | with-exec echo,"hello" | stdout'
dagger # interactive shell (REPL)
# Dagger Functions / modules
dagger init --sdk=python # scaffold a module in the cwd
dagger develop # generate SDK bindings
dagger functions # list callable functions
dagger call <function> --arg=value # invoke a function
# GraphQL API directly
dagger query <<'EOF'
{ container { from(address:"alpine") { withExec(args:["uname","-a"]) { stdout } } } }
EOF
See the Dagger documentation for the full API — modules in Go / Python / TypeScript, the type system, caching, services, and secrets.
The kit works fully without Dagger Cloud. Cloud adds hosted trace visualization (a web URL for each run) — it's observability, not a requirement, so it's off by default: no token means no tracing, and pipelines run exactly the same.
To turn it on, store your Dagger Cloud token once with sbx's secret manager (the token is never baked into the kit):
echo "$DAGGER_CLOUD_TOKEN" | sbx secret set -g dagger-cloud # -g = all sandboxes
On the next sbx run with this kit, sbx asks you to approve binding the dagger-cloud credential;
the token is authorized by the sbx proxy on requests to api.dagger.cloud (already in this kit's
caps.network.allow). Get a token from https://dagger.cloud.
Note: the Dagger CLI/engine decide whether to emit traces based on the presence of
DAGGER_CLOUD_TOKENin the environment. If tracing doesn't appear after binding the secret, confirm the token is reaching the sandbox asDAGGER_CLOUD_TOKEN(!env | grep DAGGER_CLOUD_TOKENinside the session) and thatapi.dagger.cloudisn't blocked by your org's governance policy.
The CLI pin (DAGGER_VERSION=v0.21.7 in spec.yaml) determines which engine image version Dagger
provisions — they must match. To bump Dagger, change that one value and republish; the engine tag
follows automatically because the CLI requests its matching engine.
If sbx run --kit docker.io/... fails with a mount-policy error like:
ERROR: failed to create sandbox: ... mount policy denied: /Users/<you>: no applicable policies for op(...)
the sbx runtime is refusing to mount your home directory. sbx run mounts the current working
directory into the sandbox, and mounting your entire home dir is blocked for safety. Run from any
directory other than your home directory.
If the first dagger command hangs for a while, that's expected — it's pulling the engine image
(hundreds of MB) from registry.dagger.io. Give it up to a minute; later runs are fast.
If a pipeline fails to pull an image with a network/DNS error, the registry it needs probably isn't
in this kit's caps.network.allow. Docker Hub, registry.dagger.io, and ghcr.io are allowed by
default; add any other registry (e.g. quay.io, a private registry) to caps.network.allow and
republish, or ask your org admin if a governance policy is overriding the allowlist.
If dagger is "command not found", it installed to ~/.local/bin; call it as ~/.local/bin/dagger
or ensure ~/.local/bin is on PATH.