OpenClawDashboard/bridge/src/routes/exec.ts
Mannu d4a3f2b869 feat: complete Tiger dashboard implementation
- Bridge: Express API server with SQLite (projects, tasks, executions, outputs)
- Dashboard: Next.js app rewired from WebSocket gateway to Tiger Bridge HTTP API
- Tasks: Kanban board with drag-drop, project management with CRUD
- Dispatch: Task dispatch to sandbox with file watcher for status updates
- UI: Container health panel, workspace browser, logs viewer, output viewer

Critical fixes:
- Use execInSandbox instead of execOnHost for container operations
- Watch symlink path instead of container-internal path
- URL-encoded params for GET requests instead of body
- PUT/DELETE support added to useBridgeRequest

Sprints 1-5 complete. Ready for VPS deployment.
2026-04-12 23:27:51 +05:30

36 lines
1 KiB
TypeScript

/**
* Exec route — POST /api/exec
* Run arbitrary commands inside the Tiger sandbox.
* Use with care — this is the raw escape hatch.
*
* Body: { command: string, timeout?: number }
*/
import { Router } from "express";
import { execInSandbox, execOnHost } from "../tiger.js";
const router = Router();
router.post("/", async (req, res) => {
const { command, timeout, target = "sandbox" } = req.body;
if (!command || typeof command !== "string") {
return res.status(400).json({ error: "Missing 'command' in request body" });
}
// Safety: block obviously destructive commands
const blocked = ["rm -rf /", "mkfs", "dd if=", ":(){ :|:& };:"];
if (blocked.some((b) => command.includes(b))) {
return res.status(403).json({ error: "Command blocked for safety" });
}
try {
const exec = target === "host" ? execOnHost : execInSandbox;
const result = await exec(command, timeout || 30_000);
res.json(result);
} catch (err: any) {
res.status(500).json({ error: err.message });
}
});
export default router;