mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 21:53:28 +08:00
P1: Log non-ENOENT spawn errors (timeout, signal kill) to stderr instead of silently exiting 0. Separate handling for result.error and null result.status so users know when the security monitor failed to run. P1: Remove "async": true from hooks.json — async hooks run in the background and cannot block tool execution. The security hook needs to be synchronous so exit(2) actually prevents credential exposure and other critical findings from proceeding. P2: Remove dead tool_response/tool_result code from extract_content. In a PreToolUse hook the tool hasn't executed yet, so tool_response is never populated. Removed the variable and the unreachable branch that appended its content. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
78 lines
2.4 KiB
JavaScript
78 lines
2.4 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* InsAIts Security Monitor — wrapper for run-with-flags compatibility.
|
|
*
|
|
* This thin wrapper receives stdin from the hooks infrastructure and
|
|
* delegates to the Python-based insaits-security-monitor.py script.
|
|
*
|
|
* The wrapper exists because run-with-flags.js spawns child scripts
|
|
* via `node`, so a JS entry point is needed to bridge to Python.
|
|
*/
|
|
|
|
'use strict';
|
|
|
|
const path = require('path');
|
|
const { spawnSync } = require('child_process');
|
|
|
|
const MAX_STDIN = 1024 * 1024;
|
|
|
|
let raw = '';
|
|
process.stdin.setEncoding('utf8');
|
|
process.stdin.on('data', chunk => {
|
|
if (raw.length < MAX_STDIN) {
|
|
raw += chunk.substring(0, MAX_STDIN - raw.length);
|
|
}
|
|
});
|
|
|
|
process.stdin.on('end', () => {
|
|
const scriptDir = __dirname;
|
|
const pyScript = path.join(scriptDir, 'insaits-security-monitor.py');
|
|
|
|
// Try python3 first (macOS/Linux), fall back to python (Windows)
|
|
const pythonCandidates = ['python3', 'python'];
|
|
let result;
|
|
|
|
for (const pythonBin of pythonCandidates) {
|
|
result = spawnSync(pythonBin, [pyScript], {
|
|
input: raw,
|
|
encoding: 'utf8',
|
|
env: process.env,
|
|
cwd: process.cwd(),
|
|
timeout: 14000,
|
|
});
|
|
|
|
// ENOENT means binary not found — try next candidate
|
|
if (result.error && result.error.code === 'ENOENT') {
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!result || (result.error && result.error.code === 'ENOENT')) {
|
|
process.stderr.write('[InsAIts] python3/python not found. Install Python 3.9+ and: pip install insa-its\n');
|
|
process.stdout.write(raw);
|
|
process.exit(0);
|
|
}
|
|
|
|
// Log non-ENOENT spawn errors (timeout, signal kill, etc.) so users
|
|
// know the security monitor did not run — fail-open with a warning.
|
|
if (result.error) {
|
|
process.stderr.write(`[InsAIts] Security monitor failed to run: ${result.error.message}\n`);
|
|
process.stdout.write(raw);
|
|
process.exit(0);
|
|
}
|
|
|
|
if (result.stdout) process.stdout.write(result.stdout);
|
|
if (result.stderr) process.stderr.write(result.stderr);
|
|
|
|
// result.status is null when the process was killed by a signal or
|
|
// timed out. Treat that as an error rather than silently passing.
|
|
if (!Number.isInteger(result.status)) {
|
|
const signal = result.signal || 'unknown';
|
|
process.stderr.write(`[InsAIts] Security monitor killed (signal: ${signal}). Tool execution continues.\n`);
|
|
process.exit(0);
|
|
}
|
|
|
|
process.exit(result.status);
|
|
});
|