From f7b0cfb3419569f269d3cec13458ef0624267bd8 Mon Sep 17 00:00:00 2001 From: cynarAI <155274210+cynarAI@users.noreply.github.com> Date: Sun, 4 Oct 2026 17:22:56 +0200 Subject: [PATCH] fix(supervisor): treat blank computer limits as unset (#132) .env.example ships RAKAZO_COMPUTER_MEMORY, _CPUS and _PIDS_LIMIT with no value. Loaded as empty strings, they bypassed the ?? defaults and the startup validation threw, so the supervisor crashed on a fresh setup. Claude-Session: https://claude.ai/code/session_012UBam2saiShpLy5o2cy3h8 Co-authored-by: Claude --- infra/sandboxes/supervisor/src/computer-spec.test.ts | 11 +++++++++++ infra/sandboxes/supervisor/src/computer-spec.ts | 12 +++++++++--- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/infra/sandboxes/supervisor/src/computer-spec.test.ts b/infra/sandboxes/supervisor/src/computer-spec.test.ts index 7a0f125..8b59175 100644 --- a/infra/sandboxes/supervisor/src/computer-spec.test.ts +++ b/infra/sandboxes/supervisor/src/computer-spec.test.ts @@ -669,6 +669,17 @@ describe("computer resource limits", () => { expect(HostConfig.PidsLimit).toBe(2048); }); + it("falls back to the defaults when a limit is set but blank", () => { + // .env.example ships these keys with no value, which loads as "" rather than undefined. + for (const value of ["", " "]) { + for (const k of KEYS) process.env[k] = value; + const { HostConfig } = containerCreateOptions(createInput); + expect(HostConfig.Memory).toBe(2 * 1024 ** 3); + expect(HostConfig.NanoCpus).toBe(2 * 1e9); + expect(HostConfig.PidsLimit).toBe(2048); + } + }); + it("pins MemorySwap to Memory so the ceiling cannot be swapped past", () => { process.env.RAKAZO_COMPUTER_MEMORY = "1536m"; const { HostConfig } = containerCreateOptions(createInput); diff --git a/infra/sandboxes/supervisor/src/computer-spec.ts b/infra/sandboxes/supervisor/src/computer-spec.ts index 66c8f11..8e70f9b 100644 --- a/infra/sandboxes/supervisor/src/computer-spec.ts +++ b/infra/sandboxes/supervisor/src/computer-spec.ts @@ -113,19 +113,25 @@ function parsePidsLimit(name: string, raw: string): number { return value; } +/** An unset or blank variable (as .env.example ships these) means the default. */ +function limitSetting(name: string, fallback: string): string { + const value = process.env[name]; + return value?.trim() ? value : fallback; +} + /** The host resource ceilings applied to every bot computer. */ export function computerResourceLimits() { const memoryBytes = parseMemoryBytes( "RAKAZO_COMPUTER_MEMORY", - process.env.RAKAZO_COMPUTER_MEMORY ?? DEFAULT_COMPUTER_MEMORY, + limitSetting("RAKAZO_COMPUTER_MEMORY", DEFAULT_COMPUTER_MEMORY), ); const nanoCpus = parseNanoCpus( "RAKAZO_COMPUTER_CPUS", - process.env.RAKAZO_COMPUTER_CPUS ?? DEFAULT_COMPUTER_CPUS, + limitSetting("RAKAZO_COMPUTER_CPUS", DEFAULT_COMPUTER_CPUS), ); const pidsLimit = parsePidsLimit( "RAKAZO_COMPUTER_PIDS_LIMIT", - process.env.RAKAZO_COMPUTER_PIDS_LIMIT ?? DEFAULT_COMPUTER_PIDS_LIMIT, + limitSetting("RAKAZO_COMPUTER_PIDS_LIMIT", DEFAULT_COMPUTER_PIDS_LIMIT), ); return { // Memory and MemorySwap are set together: leaving MemorySwap unset lets the