From 6f885af4b45ab0f2e328b70010f6e0de56ff0379 Mon Sep 17 00:00:00 2001 From: didericis Date: Sun, 19 Jul 2026 00:49:00 -0400 Subject: [PATCH] fix(firecracker): make guest /tmp world-writable so agents can use it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The rootless agent rootfs build can land /tmp as 0755/root-owned, so the agent (uid 1000 node) can't create scratch dirs there. The sandbox-escape suite's README-push test does `cd /tmp && git init sandbox-escape-repo` and died with "cannot mkdir sandbox-escape-repo: Permission denied" — before the git-gate gitleaks hook could run — so the test read it as a missing hook. On docker the agent inherits node:22-slim's 1777 /tmp, which is why only the Firecracker path was affected (and only now that the suite runs end-to-end). Set /tmp to 1777 in the guest PID-1 init, so every agent VM boots with a usable /tmp regardless of rootfs perm drift. Also update the infra-init unit test to assert the gateway launches via the `bot_bottle.gateway_init` module (matching the prior fix), not a file path. Co-Authored-By: Claude Opus 4.8 Claude-Session: https://claude.ai/code/session_01A9qa3xoavjQScufDfZaXKR --- bot_bottle/backend/firecracker/util.py | 5 +++++ tests/unit/test_firecracker_infra_vm.py | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/bot_bottle/backend/firecracker/util.py b/bot_bottle/backend/firecracker/util.py index 425addd..5fd77c1 100644 --- a/bot_bottle/backend/firecracker/util.py +++ b/bot_bottle/backend/firecracker/util.py @@ -368,6 +368,11 @@ mount -t devtmpfs dev /dev 2>/dev/null mkdir -p /dev/pts && mount -t devpts devpts /dev/pts 2>/dev/null mount -o remount,rw / 2>/dev/null +# /tmp must be world-writable + sticky. The rootless rootfs build can land +# it 0755/root-owned, leaving the agent (uid 1000 node) unable to create +# scratch dirs there — git worktrees, build temp, `git init /tmp/...`, etc. +mkdir -p /tmp && chmod 1777 /tmp + # Install the per-bottle SSH pubkey from the kernel cmdline. KEY=$(sed -n 's/.*bb_pubkey=\([^ ]*\).*/\1/p' /proc/cmdline | base64 -d 2>/dev/null) if [ -n "$KEY" ]; then diff --git a/tests/unit/test_firecracker_infra_vm.py b/tests/unit/test_firecracker_infra_vm.py index 497b7c8..ea740d5 100644 --- a/tests/unit/test_firecracker_infra_vm.py +++ b/tests/unit/test_firecracker_infra_vm.py @@ -38,7 +38,9 @@ class TestBuildInfraRootfs(unittest.TestCase): # and exports PATH so gateway_init's subprocess daemons find python3. init = build.call_args.kwargs["init_script"] self.assertIn("bot_bottle.orchestrator", init) - self.assertIn("gateway_init.py", init) + # Gateway launches via the installed package (there is no + # /app/gateway_init.py file since the daemons moved into bot_bottle). + self.assertIn("bot_bottle.gateway_init", init) self.assertIn("export PATH=", init) # Persistent registry volume mounted at the DB dir before the CP starts. self.assertIn("/dev/vdb", init)