Skip to main content
Use isol8 to run untrusted test suites, validate pull request code, or execute user-submitted tests in a safe environment. This is useful for platforms that accept code contributions and need to verify them before merging.

Running a Test Suite

Execute a test file against user-submitted code:
import { DockerIsol8 } from "isol8";

const isol8 = new DockerIsol8({
  mode: "ephemeral",
  network: "none",
  memoryLimit: "512m",
  timeoutMs: 30000,
});

await isol8.start();

async function runTests(submittedCode: string, testCode: string) {
  const result = await isol8.execute({
    code: `
# Write the submission
with open("/sandbox/solution.py", "w") as f:
    f.write("""${submittedCode.replace(/"""/g, '\\"\\"\\"')}""")

# Write and run tests
with open("/sandbox/test_solution.py", "w") as f:
    f.write("""${testCode.replace(/"""/g, '\\"\\"\\"')}""")

import subprocess
proc = subprocess.run(
    ["python3", "-m", "pytest", "/sandbox/test_solution.py", "-v", "--tb=short"],
    capture_output=True, text=True, timeout=20
)
print(proc.stdout)
if proc.stderr:
    print(proc.stderr)
exit(proc.returncode)
`,
    runtime: "python",
    installPackages: ["pytest"],
  });

  return {
    passed: result.exitCode === 0,
    output: result.stdout,
    errors: result.stderr,
  };
}

Validating Code Before Deployment

Check that submitted code is syntactically valid and passes basic checks:
// Python syntax check
async function validatePython(code: string) {
  const result = await isol8.execute({
    code: `
import ast, sys

code = sys.stdin.read()
try:
    tree = ast.parse(code)
    print(f"Valid Python: {len(tree.body)} top-level statements")

    # Check for dangerous imports
    dangerous = {"os", "subprocess", "shutil", "socket"}
    imports = set()
    for node in ast.walk(tree):
        if isinstance(node, ast.Import):
            imports.update(a.name for a in node.names)
        elif isinstance(node, ast.ImportFrom) and node.module:
            imports.add(node.module)

    flagged = imports & dangerous
    if flagged:
        print(f"WARNING: Uses potentially dangerous modules: {flagged}")

    sys.exit(0)
except SyntaxError as e:
    print(f"Syntax error at line {e.lineno}: {e.msg}")
    sys.exit(1)
`,
    runtime: "python",
    stdin: code,
  });

  return {
    valid: result.exitCode === 0,
    message: result.stdout.trim(),
  };
}

// Node.js syntax check
async function validateJavaScript(code: string) {
  const result = await isol8.execute({
    code: `
const code = require("fs").readFileSync("/dev/stdin", "utf8");
try {
  new Function(code);
  console.log("Valid JavaScript");
  process.exit(0);
} catch (e) {
  console.log("Syntax error: " + e.message);
  process.exit(1);
}
`,
    runtime: "node",
    stdin: code,
  });

  return {
    valid: result.exitCode === 0,
    message: result.stdout.trim(),
  };
}

Running Linters

Run code quality checks on submissions:
async function lintPython(code: string) {
  const result = await isol8.execute({
    code: `
import sys
with open("/sandbox/code.py", "w") as f:
    f.write(sys.stdin.read())

import subprocess
proc = subprocess.run(
    ["python3", "-m", "flake8", "/sandbox/code.py",
     "--max-line-length=120", "--format=json"],
    capture_output=True, text=True
)
print(proc.stdout or "[]")
`,
    runtime: "python",
    stdin: code,
    installPackages: ["flake8"],
  });

  return JSON.parse(result.stdout || "[]");
}

Build Verification

Test that a Node.js package builds correctly:
async function verifyBuild(packageJson: string, indexTs: string) {
  const isol8 = new DockerIsol8({
    mode: "ephemeral",
    network: "host",        // Need network for npm install
    memoryLimit: "1g",
    timeoutMs: 120000,      // Builds can take time
    sandboxSize: "512m",
  });
  await isol8.start();

  const result = await isol8.execute({
    code: `
cd /sandbox
npm install --ignore-scripts 2>&1
npx tsc --noEmit 2>&1
echo "BUILD_STATUS: $?"
`,
    runtime: "bash",
    files: {
      "/sandbox/package.json": packageJson,
      "/sandbox/index.ts": indexTs,
      "/sandbox/tsconfig.json": JSON.stringify({
        compilerOptions: {
          strict: true,
          target: "ES2022",
          module: "ESNext",
          moduleResolution: "bundler",
        },
      }),
    },
  });

  await isol8.stop();

  const passed = result.stdout.includes("BUILD_STATUS: 0");
  return { passed, output: result.stdout, errors: result.stderr };
}

Webhook-Driven CI

Integrate isol8 into a webhook handler for GitHub PRs:
import { Hono } from "hono";
import { DockerIsol8 } from "isol8";

const app = new Hono();
const isol8 = new DockerIsol8({ mode: "ephemeral", network: "none" });
await isol8.start();

app.post("/webhook/pr", async (c) => {
  const payload = await c.req.json();

  // Extract code from PR (simplified)
  const files = payload.pull_request?.changed_files || [];

  const results = await Promise.all(
    files.map(async (file: { filename: string; content: string }) => {
      if (!file.filename.endsWith(".py")) return null;

      const result = await isol8.execute({
        code: `
import ast, sys
code = sys.stdin.read()
try:
    ast.parse(code)
    print("OK")
except SyntaxError as e:
    print(f"FAIL: {e}")
    sys.exit(1)
`,
        runtime: "python",
        stdin: file.content,
      });

      return { file: file.filename, valid: result.exitCode === 0 };
    })
  );

  return c.json({ checks: results.filter(Boolean) });
});

Cleanup After Test Runs

Use the static cleanup method to remove all containers after a test session:
import { DockerIsol8 } from "isol8";

// After your CI pipeline completes
const cleanup = await DockerIsol8.cleanup();
console.log(`Removed ${cleanup.removed} containers, ${cleanup.failed} failed`);