Skip to content

feat: make a computer's PID limit optional - #4

Merged
IshmaelRogers merged 1 commit into
mainfrom
feat/optional-computer-pids-limit
Sep 3, 2026
Merged

feat: make a computer's PID limit optional#4
IshmaelRogers merged 1 commit into
mainfrom
feat/optional-computer-pids-limit

Conversation

@IshmaelRogers

Copy link
Copy Markdown

What

EnsureOptions.pidsLimit is now number | null instead of number | undefined. Unset keeps the existing 512 default. Explicit null omits PidsLimit from the container's HostConfig entirely, wired to a new COMPUTER_PIDS_LIMIT env var (unset = default, empty string = disabled).

Why

Found running supervisor against a rootless-Docker enclave (bit-mind CopilotKit#20, standing up the execution plane this repo's gateway relays into). POST /computers/{botId}/ensure fails outright — an OCI runtime error, not a soft degradation:

OCI runtime create failed: creating container: systemd error: Interactive authentication required.

Reproduced with both runc and runsc (gVisor) — identical error, so not gVisor-specific. Reproduced with COMPUTER_MEMORY_BYTES unset too, isolating it to the unconditional PidsLimit: options.pidsLimit ?? 512 in hostConfig() — every computer this supervisor creates asks the daemon to register a PID-limited cgroup scope via its systemd driver, and that registration is what's failing. Confirmed the session D-Bus bus itself works fine when tested directly (busctl --user list, systemd-run --user --scope both succeed as the same user) — this is specifically the containerd-shim/runc subprocess's own D-Bus interaction in a rootless context, not a broken session.

Switching to cgroupdriver=cgroupfs was tried and rejected: it fails differently (cgroup.subtree_control: permission denied — the daemon isn't resolving its own delegated cgroup subtree), and rootless Docker's cgroup v2 support is designed around the systemd driver, so cgroupfs isn't the pragmatic fix.

Scope

This unblocks the product path (a deployment on an affected host can disable the limit and proceed) without touching the actual root cause, which is host-level systemd/cgroup/D-Bus configuration — a separate, out-of-repo infrastructure question. Disabling this is a real reduction in defense-in-depth, documented on the field and the env var: a deployment that disables it should compensate with run timeouts, per-run concurrency ceilings, a watchdog for leaked containers, and host-level process-count alerting.

Tests

Two new integration tests in supervisor/tests/docker.integration.test.ts (real Docker daemon, following the file's existing pattern): the unchanged 512 default, and explicit null producing no limit. Both pass against this host's Docker daemon.

bunx biome format/lint clean, bun run typecheck (supervisor) clean, bun test supervisor/tests/docker.integration.test.ts → 7 pass / 0 fail.

🤖 Generated with Claude Code

Found running supervisor against a rootless-Docker enclave (bit-mind CopilotKit#20):
container creation for every computer fails outright on a daemon whose
systemd cgroup driver cannot register a scope for a PID limit — an OCI
runtime error ("systemd error: Interactive authentication required"), not a
soft degradation. Reproduced with both runc and runsc (gVisor), and with
COMPUTER_MEMORY_BYTES unset, isolating it to the unconditional
`PidsLimit: options.pidsLimit ?? 512` in hostConfig().

`pidsLimit` on EnsureOptions is now `number | null`. Unset keeps today's
behavior (512 default). Explicit `null` omits the field from the container's
HostConfig entirely, so creation no longer depends on that cgroup path at
all. Wired to a new COMPUTER_PIDS_LIMIT env var: unset leaves the default,
set to the empty string disables the limit.

This is a real reduction in defense-in-depth on a host that needs it, not a
free choice — documented on the EnsureOptions field and the env var comment
in index.ts that a deployment disabling it should compensate elsewhere (run
timeouts, per-run concurrency ceilings, a watchdog killing leaked
containers, host-level process-count alerting).

Root cause (systemd cgroup driver + rootless Docker + D-Bus scope
registration) is a separate, host-level infrastructure question, not fixed
here — this unblocks the product path while that gets investigated.

Two new integration tests in docker.integration.test.ts (against a real
Docker daemon, following the file's existing pattern) cover both the
unchanged default and the new omission.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants