This commit is contained in:
Roger Oriol
2026-07-21 19:17:36 +02:00
parent 47436fb9bd
commit 0bb3b1c601

View File

@@ -47,7 +47,7 @@ ACTION_TOOLS = {
} }
DEFAULT_IMAGE = "agent-security-runner" DEFAULT_IMAGE = "agent-security-runner"
# §4.3 Default per-tool-call timeout. 30 minutes was far too generous # Default per-tool-call timeout. 30 minutes was far too generous
# and let a hanging command block the whole session. Lowered to 120 s # and let a hanging command block the whole session. Lowered to 120 s
# with a --tool-timeout CLI override. # with a --tool-timeout CLI override.
EXEC_TIMEOUT_S = 120 EXEC_TIMEOUT_S = 120
@@ -127,11 +127,12 @@ class DockerSandbox:
) )
self.tools_dir = Path(tools_dir).resolve() self.tools_dir = Path(tools_dir).resolve()
self.build_context = Path(build_context or self.tools_dir.parent).resolve() self.build_context = Path(
build_context or self.tools_dir.parent).resolve()
self.image = image self.image = image
self.network = network self.network = network
self.exec_timeout = float(exec_timeout) self.exec_timeout = float(exec_timeout)
# §5.2: the harness — not the model — controls the container env. # the harness — not the model — controls the container env.
# Only an allowlist of vars is inherited from the host; secret- # Only an allowlist of vars is inherited from the host; secret-
# looking env vars are stripped before the container ever starts. # looking env vars are stripped before the container ever starts.
self.container_env = container_env or {} self.container_env = container_env or {}
@@ -152,11 +153,13 @@ class DockerSandbox:
dockerfile = self.build_context / "Dockerfile" dockerfile = self.build_context / "Dockerfile"
if not dockerfile.exists(): if not dockerfile.exists():
raise DockerSandboxError( raise DockerSandboxError(
f"Cannot build sandbox image: Dockerfile not found at {dockerfile}." f"Cannot build sandbox image: Dockerfile not found at {
dockerfile}."
) )
print(f" [sandbox] building image '{self.image}' (one-time)...") print(f" [sandbox] building image '{self.image}' (one-time)...")
build = subprocess.run( build = subprocess.run(
self.runtime + ["build", "-t", self.image, str(self.build_context)], self.runtime + ["build", "-t",
self.image, str(self.build_context)],
) )
if build.returncode != 0: if build.returncode != 0:
raise DockerSandboxError( raise DockerSandboxError(
@@ -183,7 +186,7 @@ class DockerSandbox:
"-w", str(self.project_root), "-w", str(self.project_root),
] ]
# §5.2 Credential injection at the harness level: only the # Credential injection at the harness level: only the
# allowlisted env vars (set by the harness, never by the model) # allowlisted env vars (set by the harness, never by the model)
# are passed to the container. Host credentials are stripped. # are passed to the container. Host credentials are stripped.
for name, value in self.container_env.items(): for name, value in self.container_env.items():
@@ -197,17 +200,20 @@ class DockerSandbox:
run = subprocess.run(cmd, capture_output=True, text=True) run = subprocess.run(cmd, capture_output=True, text=True)
if run.returncode != 0: if run.returncode != 0:
raise DockerSandboxError( raise DockerSandboxError(
f"Could not start sandbox container: {run.stderr.strip() or run.stdout.strip()}" f"Could not start sandbox container: {
run.stderr.strip() or run.stdout.strip()}"
) )
# Sanity check: confirm the container is actually running. # Sanity check: confirm the container is actually running.
ps = subprocess.run( ps = subprocess.run(
self.runtime + ["inspect", "-f", "{{.State.Running}}", self.container], self.runtime + ["inspect", "-f",
"{{.State.Running}}", self.container],
capture_output=True, text=True, capture_output=True, text=True,
) )
if ps.returncode != 0 or ps.stdout.strip() != "true": if ps.returncode != 0 or ps.stdout.strip() != "true":
raise DockerSandboxError( raise DockerSandboxError(
f"Sandbox container '{self.container}' is not running after start." f"Sandbox container '{
self.container}' is not running after start."
) )
# -- tool execution ------------------------------------------------ # -- tool execution ------------------------------------------------
@@ -240,7 +246,8 @@ class DockerSandbox:
if proc.returncode != 0: if proc.returncode != 0:
err = (proc.stderr or proc.stdout or "").strip() err = (proc.stderr or proc.stdout or "").strip()
raise DockerSandboxError( raise DockerSandboxError(
f"Container exec for '{name}' failed (exit {proc.returncode}): {err}" f"Container exec for '{name}' failed (exit {proc.returncode}): {
err}"
) )
return proc.stdout return proc.stdout