126 lines
4.4 KiB
TypeScript
126 lines
4.4 KiB
TypeScript
/**
|
|
* Tool Sandbox PoC (Gen 2 - Production Tooling)
|
|
*
|
|
* This script proves that the execution environment can physically handle
|
|
* invoking actual production-grade tooling constraints (WASM for Tree-sitter
|
|
* and Deno.Command for Semgrep).
|
|
*
|
|
* Dependencies required on host system for this PoC:
|
|
* 1. Semgrep: `sudo pip3 install semgrep --break-system-packages`
|
|
* 2. Tree-sitter: `npm install web-tree-sitter tree-sitter-javascript`
|
|
*/
|
|
|
|
import { join, dirname, fromFileUrl } from "https://deno.land/std@0.224.0/path/mod.ts";
|
|
import * as webTreeSitter from "npm:web-tree-sitter@0.26.13";
|
|
const Parser = webTreeSitter.default || webTreeSitter.Parser;
|
|
|
|
const currentDir = dirname(fromFileUrl(import.meta.url));
|
|
const TEMP_FILE = join(currentDir, "dummy_target.js");
|
|
|
|
const DUMMY_CODE = `
|
|
function vulnerableQuery(userInput) {
|
|
const query = "SELECT * FROM users WHERE name = '" + userInput + "'";
|
|
db.execute(query);
|
|
}
|
|
`;
|
|
|
|
async function testTreeSitter() {
|
|
console.log("\n--- Testing Tree-sitter (WASM) ---");
|
|
try {
|
|
// web-tree-sitter requires initialization to load the base wasm
|
|
await Parser.init();
|
|
|
|
// Explicitly load the JavaScript language grammar WASM using a direct path
|
|
// In a real environment, this might be copied to a known static directory.
|
|
// For this PoC, we point directly to the npm installation path.
|
|
const rootDir = dirname(dirname(currentDir)); // Root of repo
|
|
const wasmPath = join(rootDir, "node_modules", "tree-sitter-javascript", "tree-sitter-javascript.wasm");
|
|
|
|
console.log(`[Sandbox] Loading Language WASM from: ${wasmPath}`);
|
|
const wasmBytes = await Deno.readFile(wasmPath);
|
|
|
|
const Lang = await webTreeSitter.Language.load(wasmBytes);
|
|
const parser = new Parser();
|
|
parser.setLanguage(Lang);
|
|
|
|
const tree = parser.parse(DUMMY_CODE);
|
|
console.log("[Sandbox] Successfully parsed syntax tree!");
|
|
console.log(`[Sandbox] Root Node Type: ${tree.rootNode.type}`);
|
|
console.log(`[Sandbox] Extracted Functions: ${tree.rootNode.children.filter(n => n.type === 'function_declaration').map(n => n.childForFieldName('name')?.text).join(', ')}`);
|
|
return true;
|
|
} catch (error) {
|
|
console.error("❌ Tree-sitter WASM execution failed:", error.message);
|
|
console.error("Please ensure you ran: `npm install web-tree-sitter tree-sitter-javascript`");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
async function testSemgrep() {
|
|
console.log("\n--- Testing Semgrep (Binary) ---");
|
|
try {
|
|
// Write out dummy file for semgrep to scan
|
|
await Deno.writeTextFile(TEMP_FILE, DUMMY_CODE);
|
|
|
|
// Define a basic semgrep rule directly via CLI flag to detect our dummy issue
|
|
const command = new Deno.Command("semgrep", {
|
|
args: [
|
|
"--quiet",
|
|
"--json",
|
|
"--lang", "javascript",
|
|
"-e", '"$SELECT ... " + $INPUT',
|
|
TEMP_FILE
|
|
],
|
|
stdout: "piped",
|
|
stderr: "piped",
|
|
});
|
|
|
|
const { code, stdout, stderr } = await command.output();
|
|
const decoder = new TextDecoder();
|
|
|
|
if (code !== 0 && code !== 1) { // 1 means findings found, 0 means no findings. Other codes are errors.
|
|
console.error("❌ Semgrep execution returned error code:", code);
|
|
console.error(decoder.decode(stderr));
|
|
return false;
|
|
}
|
|
|
|
const outputString = decoder.decode(stdout);
|
|
const jsonResult = JSON.parse(outputString);
|
|
|
|
console.log("[Sandbox] Successfully executed native semgrep binary!");
|
|
console.log(`[Sandbox] Vulnerabilities found: ${jsonResult.results.length}`);
|
|
if (jsonResult.results.length > 0) {
|
|
console.log(`[Sandbox] Details: ${jsonResult.results[0].extra.message} (Line ${jsonResult.results[0].start.line})`);
|
|
}
|
|
|
|
return true;
|
|
} catch (error) {
|
|
console.error("❌ Semgrep binary execution failed:", error.message);
|
|
console.error("Please ensure Semgrep is installed: `sudo pip3 install semgrep --break-system-packages`");
|
|
return false;
|
|
} finally {
|
|
try {
|
|
await Deno.remove(TEMP_FILE);
|
|
} catch {
|
|
// ignore
|
|
}
|
|
}
|
|
}
|
|
|
|
async function runSandbox() {
|
|
console.log("Starting Gen 2 Tool Sandbox (Production Dependencies)\n");
|
|
|
|
const tsSuccess = await testTreeSitter();
|
|
const sgSuccess = await testSemgrep();
|
|
|
|
if (tsSuccess && sgSuccess) {
|
|
console.log("\n✅ Gen 2 Sandbox execution completed successfully. Physical tools verified.");
|
|
} else {
|
|
console.error("\n❌ Gen 2 Sandbox failed due to missing or malfunctioning host dependencies.");
|
|
Deno.exit(1);
|
|
}
|
|
}
|
|
|
|
if (import.meta.main) {
|
|
runSandbox().catch(console.error);
|
|
}
|