feat(worker): container execution backend with resource limits and hosted gate (#5)#59
Merged
Merged
Conversation
…sted gate (#5) Closes #5. New crates/worker/src/backend.rs: a WorkerBackend seam behind the session launch. The host backend keeps today's direct execution for development and trusted self-hosting; worker.backend = "container" runs each task attempt in a fresh, uniquely named container via any docker-compatible CLI: - hardened profile: --read-only rootfs, --cap-drop ALL, no-new-privileges, bounded /tmp tmpfs, only the task workspace bind-mounted - resource limits: --cpus / --memory / --pids-limit / --network, all operator-configurable under [worker.container] - git authority forwarded by env var NAME (-e COVEN_GIT_TOKEN): the token never enters argv, docker inspect, or shell history - wall-clock enforcement kills the CLI and then the container by name; --rm plus explicit kill guarantee teardown; exit 137 is surfaced as a probable memory-limit kill in the failure detail - the session brief references the workspace as the sandbox sees it (/workspace), not the host path Hosted gate: once [[installations]] exist (hosted posture), doctor refuses worker.backend = "host" unless allow_host_backend = true is set deliberately. Container mode validates the runtime CLI and image. Workspace teardown is now tested on both paths (success in the publication gate harness, failure via an exit-2 session), and a fake docker CLI proves the isolation argv, env-only token, result copy-out from the bind mount, and kill-by-name on timeout. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a worker execution backend abstraction to support running each coven-code --headless attempt inside a hardened, resource-limited container for hosted deployments, while preserving the existing host-execution path for development/self-hosting and gating host execution in “hosted posture” via config diagnostics.
Changes:
- Introduces a
Backendabstraction withHostandContainerbackends, plus a pinned container isolation argv profile and timeout teardown behavior. - Extends worker configuration (
worker.backend,worker.container.*,worker.allow_host_backend) and updatesdoctorchecks to refuse host execution by default when[[installations]]are configured. - Updates documentation and examples to describe the new backends and operator configuration; adds tests asserting isolation argv, token forwarding channel, timeout kill-by-name, and workspace cleanup.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Adds a capability row documenting container isolation support and hosted posture behavior. |
| docs/container-isolation.md | Documents operator-facing config for selecting the container backend and its isolation properties. |
| crates/worker/src/lib.rs | Routes session launches through the new backend seam; adds container backend and cleanup assertions in tests. |
| crates/worker/src/backend.rs | Implements host/container execution backends, docker argv construction, and timeout teardown mechanics. |
| crates/webhook/src/routes.rs | Updates test configs to include new worker backend fields. |
| crates/config/src/lib.rs | Adds new worker backend/container config types and doctor validation for hosted posture gating. |
| config/example.toml | Documents the new worker backend/container settings in the sample config. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+9
to
+11
| //! Git authority is injected by environment variable *name* (`-e NAME` | ||
| //! inherits the value from the docker CLI's own environment), so the token | ||
| //! never appears in any argv, container inspect output, or shell history. |
Comment on lines
+202
to
+211
| if let Some(kill) = kill { | ||
| match Command::new(&kill.docker_bin) | ||
| .args(["kill", &kill.name]) | ||
| .output() | ||
| .await | ||
| { | ||
| Ok(_) => {} | ||
| Err(e) => warn!(container = %kill.name, "docker kill failed: {e}"), | ||
| } | ||
| } |
Comment on lines
+87
to
+90
| bounded `/tmp` tmpfs, and only the task workspace bind-mounted. Git | ||
| authority is forwarded by environment variable *name* (`-e COVEN_GIT_TOKEN`) | ||
| so the token never appears in argv or `docker inspect`. On timeout the | ||
| adapter kills both the CLI process and the container by name; `--rm` tears |
BunsDev
added a commit
that referenced
this pull request
Jul 7, 2026
* feat(github): branch listing, compare, head-PR lookup, ref deletion, labels (#14) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com> * feat(gardener): branch classifier, policy planner, and schedule parsing (#14) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com> * feat(config): per-repo gardener policy with validation (#14) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com> * feat(webhook): garden command and GardenRun task kind (#14) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com> * feat(worker): execute gardener plans — scan, prune with SHA guard, surface draft PRs (#14) Replace the GardenRun stub with a real execution path: scan branches against the resolved per-repo policy, classify and plan, prune dead and merged branches (re-checking the SHA before every delete), surface PR-less human branches as labeled draft PRs, and post the run report on the report issue. Bot-only PR-less branches are skipped, and the whole runner stays behind the write-permission command gate. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com> * chore(tests): carry WorkerConfig and Config struct drift across the rebase Main added backend/container/allow_host_backend to WorkerConfig (#59) while this branch added the gardener section to Config; fill both sides in the test literals that construct the structs directly. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com> * feat: schedule Branch Gardener runs (#14) Wire configured gardener schedules into the server, support /coven garden, and update shipped docs/status. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Signed-off-by: Val Alexander <bunsthedev@gmail.com> --------- Signed-off-by: Val Alexander <bunsthedev@gmail.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #5 — the largest infra item in the wave; unblocks #12.
What lands
crates/worker/src/backend.rs— a backend seam behind the session launch:worker.backend = "container"): one fresh, uniquely-named container per task attempt through any docker-compatible CLI (docker / podman / nerdctl)The isolation profile (pinned by a pure-argv test):
--read-onlyrootfs ·--cap-drop ALL·no-new-privileges· bounded/tmptmpfs · only the task workspace bind-mounted ·--cpus/--memory/--pids-limit/--networklimitsSecurity details:
-e COVEN_GIT_TOKEN) — the token never enters argv,docker inspect, or shell history (asserted end-to-end)--rm+ explicit kill guarantee teardown/workspace— the sandbox's view — never host pathsHosted gate:
[[installations]]configured +backend = "host"→ doctor error unlessallow_host_backend = trueis set deliberately. Container mode validates the CLI binary and image.Acceptance criteria → proof
hosted_posture_refuses_the_host_backend_without_explicit_opt_in--rmin pinned argvworkspace_is_destroyed_when_the_session_failsredactpipeline covers all copied-out surfaces; token-not-in-argv assertedVerification
219 tests green · clippy
-D warningsclean · python gates green · demo 21/21 (host backend default — proves back-compat)