You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
feat(deploy): start agents through a separate provisioner service - #48
First cut of CL-11875 (steps 1–2 of the attached plan). Draft: the rest of the plan (tools inside agent containers, agent network and egress proxy, placement declarations, Landlock) lands on this PR before it is ready.
What changed
New apps/sidecar-provisioner: the compose service sidecar-provisioner, the only container with the Docker socket. It serves ensure/destroy behind a shared secret and reuses Builder's Docker provisioner (moved from the hub, hardening unchanged).
The hub gets a forwarding provisioner (Interchange contract, apiVersion 2). With SIDECAR_PROVISIONER_URL set, it is the only provisioner: no agents run in the hub. An unreachable service rejects placement with sidecar_provisioner_unreachable and wording the person sees.
Compose: the hub has no socket mount or group_add; compose.docker-sidecars.yml is removed; SIDECAR_PROVISIONER_TOKEN is a new required secret.
The hub reads the service's Docker binding fingerprint and capabilities from an authenticated GET /binding at startup and registers with them, so Interchange notices a changed Docker backend; a service restarted with a different setup refuses new agents with sidecar_provisioner_binding_changed. Compose starts the hub only once the provisioner is healthy.
A wrong or short token (under 32 characters) and malformed requests get clear, configured errors.
Verified
lint, format:check, typecheck, test (73 pass), vendor:verify, pins:verify.
Independent review; its findings are fixed (binding fingerprint, error mapping, shared Docker setup, token length).
A throwaway compose stack built from source: docker inspect shows the hub with no socket and the provisioner holding it; creating a project starts one hardened agent container (read-only root, all caps dropped, no-new-privileges, memory/PID/CPU limits, own volume) that connects to the hub; with the provisioner stopped, project creation returns sidecar_provisioner_unreachable with the person-facing message; after restart, creation succeeds; a wrong token and changed limits each give their configured message and start no second container.
Known gaps (later steps)
Tool calls inside agent containers still fail (sandbox runtime under dropped caps).
Agent containers reach the hub via host.docker.internal; Linux needs the agent network.
Design preview drafts read the local sidecar's disk, which the Docker install no longer has.
Blocking: the provisioner starts the container, and coder and designer tools still cannot run inside it.
apps/sidecar-provisioner/src/docker.ts creates the sidecar with CapDrop: ["ALL"] and SecurityOpt: ["no-new-privileges"], and dockerSidecarCapabilities reports runtime:posix as available. Compose sets SIDECAR_PROVISIONER_URL, so the hub no longer starts these processes. Bubblewrap then fails with bwrap: No permissions to create a new namespace or bwrap: setting up uid map: Permission denied.
docs/SELF_HOST.md already says that container needs seccomp=unconfined, apparmor=unconfined, and systempaths=unconfined. Those exemptions are still only on the hub service in deploy/compose.yml, which is not the process running the tools. A container that starts is not the tools working.
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
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.
First cut of CL-11875 (steps 1–2 of the attached plan). Draft: the rest of the plan (tools inside agent containers, agent network and egress proxy, placement declarations, Landlock) lands on this PR before it is ready.
What changed
apps/sidecar-provisioner: the compose servicesidecar-provisioner, the only container with the Docker socket. It serves ensure/destroy behind a shared secret and reuses Builder's Docker provisioner (moved from the hub, hardening unchanged).SIDECAR_PROVISIONER_URLset, it is the only provisioner: no agents run in the hub. An unreachable service rejects placement withsidecar_provisioner_unreachableand wording the person sees.group_add;compose.docker-sidecars.ymlis removed;SIDECAR_PROVISIONER_TOKENis a new required secret.GET /bindingat startup and registers with them, so Interchange notices a changed Docker backend; a service restarted with a different setup refuses new agents withsidecar_provisioner_binding_changed. Compose starts the hub only once the provisioner is healthy.Verified
docker inspectshows the hub with no socket and the provisioner holding it; creating a project starts one hardened agent container (read-only root, all caps dropped, no-new-privileges, memory/PID/CPU limits, own volume) that connects to the hub; with the provisioner stopped, project creation returnssidecar_provisioner_unreachablewith the person-facing message; after restart, creation succeeds; a wrong token and changed limits each give their configured message and start no second container.Known gaps (later steps)
host.docker.internal; Linux needs the agent network.