fix(security): block docker socket from sandboxed shell; disable opencode batch_tool

two real CI failures on main, both shipping bugs in the action:

1. `token-exfil-claude` was a real sandbox escape: GHA `ubuntu-latest`
   puts `runner` in the `docker` group, so a sandboxed shell could run
   `docker run --pid=host --privileged busybox cat /proc/<parent>/environ`
   and read the action process's env (which holds user secrets) — fully
   bypassing the unshare PID-namespace. fix: inside the sandbox's mount
   namespace (already private via `--mount-proc` which implies `--mount`),
   bind-mount /dev/null over /var/run/docker.sock (+ podman/containerd/crio
   variants) so any container-runtime socket connect from the sandbox fails.
   only affects sandboxed shells — host runner mount table is untouched, so
   user workflow steps outside pullfrog keep working.

2. `restricted-opencode` regressed in #719 (`experimental.batch_tool`).
   opencode's batch tool rejects MCP tools with `"Tool '<name>' not in
   registry. External tools (MCP, environment) cannot be batched."` when a
   model emits parallel `pullfrog_shell` (or any MCP) tool_use blocks,
   opencode internally routes them through batch, they all fail, the model
   misreads the error as "the tool doesn't exist", and gives up. caught by
   a `lens:` subagent in the restricted test concluding shell was
   unavailable and setting `DIAGNOSTIC_ID=empty`. drop `batch_tool: true`
   and the matching opencode-specific guidance in `instructions.ts` — native
   parallel tool_use (multiple tool_use blocks per assistant message) still
   works for both built-in and MCP tools without batch, so we lose only the
   1-25 wrapper, not parallelism.
This commit is contained in:
Colin McDonnell
2026-05-16 15:40:44 +00:00
committed by pullfrog[bot]
parent efc1b67e7b
commit c0988e35b0
3 changed files with 46 additions and 16 deletions
+13 -9
View File
@@ -135,15 +135,19 @@ function buildSecurityConfig(ctx: AgentRunContext, model: string | undefined): s
log.info(`» subagent models: reviewfrog=${reviewerModel}`);
return cfg;
})(),
// opt into opencode's experimental `batch` tool (added in
// anomalyco/opencode PR #2983, opt-in via `experimental.batch_tool`). it
// exposes a single `batch` tool that runs 1-25 independent tool calls
// (read/grep/glob/bash/etc.) concurrently in one assistant turn, which
// collapses the dominant grep→20×read pattern into a single round trip.
// edits are explicitly disallowed inside the batch upstream. paired with
// the "Parallel tool execution" guidance in utils/instructions.ts so the
// model actually reaches for it. see wiki/prompt.md.
experimental: { batch_tool: true },
// NOTE: `experimental.batch_tool` was enabled in #719 to bundle 1-25
// independent tool calls into one round trip, but the batch tool rejects
// MCP/"external" tools with `"Tool '<name>' not in registry. External
// tools (MCP, environment) cannot be batched - call them directly."`
// (anomalyco/opencode PR #2983 design). when a model emits parallel
// tool_use blocks containing `pullfrog_*` calls, opencode internally
// routes them through batch — they all fail, the model misreads the
// error as "the tool doesn't exist", and gives up. caught in CI by
// `restricted-opencode` after a `lens:` subagent dispatched parallel
// `pullfrog_shell` calls and concluded shell was unavailable.
// native parallel tool_use (multiple tool_use blocks per assistant
// message) still works without batch_tool for both built-in and MCP
// tools, so we lose only the batch wrapper, not parallelism.
// gemini-3 thinking pinned to high for review depth; gpt and anthropic
// effort set elsewhere (gpt: upstream default, anthropic: --effort flag in claude.ts).
provider: { google: { models: geminiHighThinkingOverrides() } },