# Isolator CLI
`isolator` is a command-line tool written in Go designed to execute code snippets (Python, Go, JavaScript) within secure, ephemeral Docker containers. It enforces resource limits, timeouts, and security constraints, making it suitable as a backend for code execution sandboxing environments like the `isolator-mcp` server.
## Features
* Executes code for specified languages (Python, Go, JavaScript).
* Uses Docker containers for strong isolation.
* Copies code files into the container using `docker cp` (via tar stream) rather than bind mounts to avoid common permission issues.
* Enforces security constraints:
* Network isolation (`--network=none` by default).
* Read-only root filesystem (`--read-only=true` by default).
* Dropped Linux capabilities (`--cap-drop=ALL` by default).
* No new privileges (`no-new-privileges:true`).
* Enforces resource limits:
* Timeout (`--timeout`).
* Memory limit (`--memory`).
* CPU limit (`--cpus`).
* Process limit (`--pids-limit`).
* Returns results (status, exit code, stdout, stderr, duration) in JSON format.
* Optional: Can commit the container to a new image on success (`--save-image`).
* Optional: Can output a basic Dockerfile used (`--save-dockerfile`).
## Installation
1. Ensure Go is installed (version 1.18+ recommended).
2. Clone the repository (or ensure source code is present).
3. Navigate to the project directory: `cd /path/to/isolator`
4. Build the binary:
```bash
go build -o isolator github.com/user/isolator
```
5. Place the resulting `isolator` binary in a location accessible via your system's `PATH`, or call it directly using its full path.
## Usage
The primary command is `run`.
```
isolator run [flags]
```
### Flags
* `--language, -l` (string, **required**): Language of the code (python, go, javascript).
* `--dir, -d` (string, **required**): Path to the host directory containing input files. This directory's contents will be copied into the container.
* `--entrypoint, -e` (string, **required**): Filename of the entrypoint script *within* the directory specified by `--dir`.
* `--container-workdir` (string, **required**): Absolute path inside the container where files will be copied and execution will happen (e.g., `/workspace`).
* `--timeout, -t` (duration, optional, default: 60s): Maximum execution time (e.g., `30s`, `1m`).
* `--memory, -m` (int, optional, default: 256): Memory limit in MB.
* `--cpus, -c` (float, optional, default: 0.5): CPU limit (e.g., 0.5 for half a core, 1 for a full core).
* `--pids-limit` (int, optional, default: 64): Maximum number of processes allowed in the container.
* `--network` (string, optional, default: "none"): Container network mode (e.g., "none", "bridge"). **Use "none" for maximum security unless network access is explicitly required.**
* `--read-only` (bool, optional, default: true): Mount container root filesystem as read-only. The working directory where files are copied is still writable.
* `--cap-drop` (string slice, optional, default: ["ALL"]): Linux capabilities to drop.
* `--runtime` (string, optional, default: "docker"): Container runtime (currently only "docker" is implicitly supported).
* `--save-image` (string, optional): Tag to save the container image as on success (e.g., `my-image:v1`).
* `--save-dockerfile` (string, optional): Path to save the base Dockerfile used.
### Example
```bash
# Assuming /path/to/code contains main.py
./isolator run \
--language python \
--dir /path/to/code \
--entrypoint main.py \
--container-workdir /app \
--timeout 30s
```
### Output
The command prints a JSON object to `stdout` containing the execution result:
```json
{
"status": "success", // "success", "timeout", or "error"
"exitCode": 0,
"stdout": "Output from the script...\n",
"stderr": "",
"durationMs": 520,
"error": null, // or error message string if status is "error" or "timeout"
"imageTag": null // or the tag if --save-image was used and successful
}
```
## Architecture
* Built using Go and the Cobra CLI library.
* Uses the official Docker Go SDK (`github.com/docker/docker/client`) to interact with the Docker daemon.
* Creates a container based on the specified language's base image.
* Creates an in-memory tar archive of the source directory provided via `--dir`.
* Uses the `CopyToContainer` Docker API to copy the tar archive into the specified `--container-workdir` within the container *after* the container is created but *before* it is started.
* Starts the container.
* Waits for container completion or timeout.
* Retrieves container logs (stdout/stderr).
* Removes the container automatically.
* Formats and prints the result as JSON.
This `CopyToContainer` approach avoids common permission issues associated with bind mounts when the host user differs from the container user.
**Note:** This tool expects the required Docker base images (e.g., `python:3.11-alpine`, `golang:1.21-alpine`) to be already pulled on the host system. It does not automatically pull missing images. You can pull images using `docker pull <image_name>`.