Running a Test Suite
Execute a test file against user-submitted code:Copy
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:Copy
// 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:Copy
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:Copy
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:Copy
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:Copy
import { DockerIsol8 } from "isol8";
// After your CI pipeline completes
const cleanup = await DockerIsol8.cleanup();
console.log(`Removed ${cleanup.removed} containers, ${cleanup.failed} failed`);