Skip to content

feat: add code execution sandbox for data tasks #789

Description

@avoidwork

Summary

Add a dedicated code execution sandbox for data tasks — running Python/R for data analysis, executing Node.js scripts for transformations, and safe computation without full shell access.

Motivation

The existing shell tool provides general command execution, but it is not designed for data-focused workflows. Office and marketing workflows frequently need to: run Python scripts for data analysis (pandas, numpy), execute R scripts for statistics, transform data with Node.js scripts, and perform safe computation without exposing the full shell. Currently the agent must use the shell tool directly, which lacks the safety guarantees, resource limits, and structured output that a dedicated data sandbox would provide.

Proposed Solution

Create a code execution sandbox tool:

  • Python Execution: Run Python code with access to common data libraries (pandas, numpy, scipy, matplotlib)
  • R Execution: Run R code with access to common statistical packages (dplyr, ggplot2, tidyr)
  • Node.js Execution: Run Node.js scripts for data transformation and manipulation
  • Safe Computation: Resource limits (CPU, memory, time), no file system access beyond sandbox, no network access unless explicitly enabled
  • Structured Output: Return results as JSON, CSV, or markdown tables
  • Artifact Management: Save output files (charts, reports) to a designated directory

Each tool should follow the existing tool pattern in src/tools/ — a zod schema, an impl function, and registration in index.js with appropriate permissions (process:spawn, filesystem:read/write within sandbox).

Alternatives Considered

  • Shell-based execution: no resource limits, no structured output, full system access is a security risk.
  • Rely on the sandbox tool: designed for skill execution, not ad-hoc data analysis.
  • Web-based computation: adds infrastructure complexity for a local-first tool.

OpenSpec Note

This project uses OpenSpec for feature development. If this request is approved, I will:

  1. Run /opsx:propose to generate a full proposal with specs and tasks
  2. Iterate on the design before any code is written
  3. Follow the task-driven implementation workflow

Additional Context

This should integrate with the spreadsheet computation gap (#782) — e.g., running Python analysis on spreadsheet data and returning results as a new spreadsheet. The existing sandbox infrastructure (src/sandbox/) provides the foundation; this tool would add a data-focused abstraction layer on top.

Dependencies

  • Python: System dependency — Python 3.10+ with pip. Data libraries installed via pip: pandas, numpy, scipy, matplotlib, seaborn. These are pre-compiled wheels for most platforms.
  • R: System dependency — R 4.3+ with CRAN packages: dplyr, ggplot2, tidyr, readr, purrr. Installed via R's package manager.
  • Node.js: Already available (Node.js 24+ required by project). Additional packages: csv-parser, json2csv for data transformation.
  • Sandbox isolation: Use Linux namespaces (unshare) or Docker containers for process isolation. Docker preferred for consistent isolation across platforms (Linux, macOS, Windows via Docker Desktop).
  • Timeout enforcement: child_process.spawn with timeout option, plus a watchdog process that kills the sandbox if it exceeds the time limit.

Testing Strategy

  • Unit tests: Mock the sandbox runner to verify input validation, output parsing, and error handling. Verify Zod schema validation for all inputs.
  • Integration test: Spin up a Docker container with Python, R, and Node.js installed. Execute simple scripts (print, math, CSV read/write) and verify output.
  • Resource limit tests: Execute a script that consumes excessive memory or CPU and verify that the sandbox kills it within the configured timeout.
  • Security tests: Execute a script that attempts to access the network, read arbitrary files, or spawn child processes — verify all are blocked.
  • Edge cases: Empty input, syntax errors, missing libraries, long-running computations, large output (thousands of rows), non-UTF-8 output.

Security Considerations

  • Process isolation: Run all code execution inside a Docker container with no network access (unless explicitly enabled), no host filesystem access (only a designated sandbox directory), and resource limits (CPU: 2 cores, memory: 2GB).
  • No shell access: The sandbox should not expose a shell. Code is passed via stdin or a temporary file, executed, and output captured. No eval(), exec(), or system() calls on the host.
  • Network isolation: Default to no network access. If network access is required, use a separate container with controlled outbound access (whitelist domains).
  • File system isolation: Only allow read/write within a designated sandbox directory (e.g., /tmp/madz-sandbox/). Validate all file paths against this directory.
  • Timeout enforcement: Hard timeout via Docker's --timeout flag or a watchdog process. Default: 60 seconds. Configurable per execution.
  • Resource limits: Docker memory limit (2GB), CPU limit (2 cores), and no swap. Prevent fork bombs by limiting the number of child processes (via seccomp profile or cgroups).
  • Input sanitization: Validate the code input against a safe subset (no import os, no subprocess, no requests, no urllib). For Python: use ast.parse to detect dangerous imports before execution. For R: disable system() and pipe operators. For Node.js: disable require() for non-whitelisted modules.
  • Output sanitization: Strip ANSI escape codes, limit output size (default: 1MB), and sanitize for XSS if output is rendered in the TUI.

Implementation Notes

  • Split into one tool with language variants: A single code tool with a language field ("python", "r", "node") keeps the API simple. Each language runs in its own Docker container image.
  • Zod schema: { language: "python" | "r" | "node", code: z.string(), timeout?: number, network?: boolean, outputPath?: string }.
  • Docker images: Pre-build images for each language with required libraries installed. Tag with version for reproducibility. Pull from a local registry or build on first use.
  • Output format: Default to JSON. Allow specifying output format: "json", "csv", "markdown". For Python: convert pandas DataFrames to JSON/CSV automatically. For R: convert data frames similarly. For Node.js: serialize the return value.
  • Artifact management: Save output files (charts, reports) to a designated directory (e.g., /tmp/madz-artifacts/). Return file paths in the response.
  • Integration with feat: add spreadsheet computation and analysis #782: The spreadsheet tool can pass data to the code sandbox as a CSV file, run analysis, and return results as a new CSV/JSON that the spreadsheet tool consumes.
  • CI considerations: Docker must be available in CI. Use docker-in-docker or a Docker socket mount. Skip integration tests if Docker is not available.
  • Fallback: If Docker is not available, fall back to running code in a chroot or via the existing sandbox tool with stricter limits. Document this as a known limitation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions