mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-03-30 13:43:26 +08:00
fix: address cubic-dev-ai + coderabbit round 3 review
cubic-dev-ai P2: dev_mode now defaults to "false" (strict mode). Users opt in to dev mode by setting INSAITS_DEV_MODE=true. cubic-dev-ai P2: Move null-status check above stdout/stderr writes in wrapper so partial/corrupt output is never leaked. Pass through original raw input on signal kill, matching the result.error path. coderabbit major: Wrap insAItsMonitor() and send_message() in try/except so SDK errors don't crash the hook. Logs warning and exits 0 (fail-open) on exception. coderabbit nitpick: write_audit now creates a new dict (enriched) instead of mutating the caller's event dict. coderabbit nitpick: Extract magic numbers to named constants: MIN_CONTENT_LENGTH=10, MAX_SCAN_LENGTH=4000, DEFAULT_MODEL. Also: added env var documentation to module docstring. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -36,6 +36,12 @@ How it works:
|
||||
Exit code 2 = critical issue found (blocks tool execution).
|
||||
Stderr output = non-blocking warning shown to Claude.
|
||||
|
||||
Environment variables:
|
||||
INSAITS_DEV_MODE Set to "true" to enable dev mode (no API key needed).
|
||||
Defaults to "false" (strict mode).
|
||||
INSAITS_MODEL LLM model identifier for fingerprinting. Default: claude-opus.
|
||||
INSAITS_VERBOSE Set to any value to enable debug logging.
|
||||
|
||||
Detections include:
|
||||
- Credential exposure (API keys, tokens, passwords)
|
||||
- Prompt injection patterns
|
||||
@@ -75,7 +81,11 @@ try:
|
||||
except ImportError:
|
||||
INSAITS_AVAILABLE = False
|
||||
|
||||
# --- Constants ---
|
||||
AUDIT_FILE: str = ".insaits_audit_session.jsonl"
|
||||
MIN_CONTENT_LENGTH: int = 10
|
||||
MAX_SCAN_LENGTH: int = 4000
|
||||
DEFAULT_MODEL: str = "claude-opus"
|
||||
|
||||
|
||||
def extract_content(data: Dict[str, Any]) -> Tuple[str, str]:
|
||||
@@ -113,14 +123,20 @@ def extract_content(data: Dict[str, Any]) -> Tuple[str, str]:
|
||||
|
||||
|
||||
def write_audit(event: Dict[str, Any]) -> None:
|
||||
"""Append an audit event to the JSONL audit log."""
|
||||
"""Append an audit event to the JSONL audit log.
|
||||
|
||||
Creates a new dict to avoid mutating the caller's *event*.
|
||||
"""
|
||||
try:
|
||||
event["timestamp"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime())
|
||||
event["hash"] = hashlib.sha256(
|
||||
json.dumps(event, sort_keys=True).encode()
|
||||
enriched: Dict[str, Any] = {
|
||||
**event,
|
||||
"timestamp": time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()),
|
||||
}
|
||||
enriched["hash"] = hashlib.sha256(
|
||||
json.dumps(enriched, sort_keys=True).encode()
|
||||
).hexdigest()[:16]
|
||||
with open(AUDIT_FILE, "a", encoding="utf-8") as f:
|
||||
f.write(json.dumps(event) + "\n")
|
||||
f.write(json.dumps(enriched) + "\n")
|
||||
except OSError as exc:
|
||||
log.warning("Failed to write audit log %s: %s", AUDIT_FILE, exc)
|
||||
|
||||
@@ -166,22 +182,29 @@ def main() -> None:
|
||||
text, context = extract_content(data)
|
||||
|
||||
# Skip very short content (e.g. "OK", empty bash results)
|
||||
if len(text.strip()) < 10:
|
||||
if len(text.strip()) < MIN_CONTENT_LENGTH:
|
||||
sys.exit(0)
|
||||
|
||||
if not INSAITS_AVAILABLE:
|
||||
log.warning("Not installed. Run: pip install insa-its")
|
||||
sys.exit(0)
|
||||
|
||||
monitor: insAItsMonitor = insAItsMonitor(
|
||||
session_name="claude-code-hook",
|
||||
dev_mode=os.environ.get("INSAITS_DEV_MODE", "true").lower() in ("1", "true", "yes"),
|
||||
)
|
||||
result: Dict[str, Any] = monitor.send_message(
|
||||
text=text[:4000],
|
||||
sender_id="claude-code",
|
||||
llm_id=os.environ.get("INSAITS_MODEL", "claude-opus"),
|
||||
)
|
||||
# Wrap SDK calls so an internal error does not crash the hook
|
||||
try:
|
||||
monitor: insAItsMonitor = insAItsMonitor(
|
||||
session_name="claude-code-hook",
|
||||
dev_mode=os.environ.get(
|
||||
"INSAITS_DEV_MODE", "false"
|
||||
).lower() in ("1", "true", "yes"),
|
||||
)
|
||||
result: Dict[str, Any] = monitor.send_message(
|
||||
text=text[:MAX_SCAN_LENGTH],
|
||||
sender_id="claude-code",
|
||||
llm_id=os.environ.get("INSAITS_MODEL", DEFAULT_MODEL),
|
||||
)
|
||||
except Exception as exc:
|
||||
log.warning("SDK error, skipping security scan: %s", exc)
|
||||
sys.exit(0)
|
||||
|
||||
anomalies: List[Any] = result.get("anomalies", [])
|
||||
|
||||
|
||||
@@ -62,16 +62,18 @@ process.stdin.on('end', () => {
|
||||
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.
|
||||
// timed out. Check BEFORE writing stdout to avoid leaking partial
|
||||
// or corrupt monitor output. Pass through original raw input instead.
|
||||
if (!Number.isInteger(result.status)) {
|
||||
const signal = result.signal || 'unknown';
|
||||
process.stderr.write(`[InsAIts] Security monitor killed (signal: ${signal}). Tool execution continues.\n`);
|
||||
process.stdout.write(raw);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
if (result.stdout) process.stdout.write(result.stdout);
|
||||
if (result.stderr) process.stderr.write(result.stderr);
|
||||
|
||||
process.exit(result.status);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user