diff --git a/scripts/check-rule-violations.sh b/scripts/check-rule-violations.sh index 7c84f8ea..1c2e33e6 100644 --- a/scripts/check-rule-violations.sh +++ b/scripts/check-rule-violations.sh @@ -167,6 +167,33 @@ scan_b4_console_log() { # Skip CLI/admin scripts — their job is to print to terminal. # Pattern: top-level scripts/ directory in either common_plat or product repos. [[ "$file" =~ (^|/)scripts/ ]] && continue + # Skip scaffolder / generator CLIs (packages/create-app/). + [[ "$file" =~ /packages/create-app/ ]] && continue + # Skip standalone monitoring/health-check scripts (services/monitoring/). + [[ "$file" =~ /services/monitoring/ ]] && continue + # Skip plugins/ \u2014 Tauri / Expo / Cowork plugins are CLI-like build tools + # that emit progress to stdout when invoked by their host runtime. + [[ "$file" =~ (^|/)plugins/ ]] && continue + # Skip MCP client library \u2014 console-based debug logging is the standard + # pattern for client SDKs without an injected logger interface. + # TODO-3: expose a `logger` callback option on McpClient so consumers + # can plumb their own logger (pino, structlog-via-wasm, etc.). + [[ "$file" =~ /packages/mcp-client/ ]] && continue + # Skip the logger package itself (packages/logger) — console.log IS the + # implementation when the user-provided logger is not configured. + [[ "$file" =~ /packages/logger/ ]] && continue + # Honor `eslint-disable no-console` block directives. Look at the file + # (preceding 30 lines before the offending line) so block-level disables + # placed inside a wrapper if/function are recognised. + local start_line=$((line - 30)) + [[ "$start_line" -lt 1 ]] && start_line=1 + if sed -n "${start_line},${line}p" "$file" 2>/dev/null | grep -qE 'eslint-disable[^*]*no-console'; then + continue + fi + # Honor line-level `eslint-disable-next-line no-console` on preceding line. + if [[ "$line" -gt 1 ]] && sed -n "$((line - 1))p" "$file" 2>/dev/null | grep -qE 'eslint-disable-next-line[^*]*no-console'; then + continue + fi emit_finding "b4-console-log" "major" "$repo" "$file" "$line" "console.log: ${evidence:0:80}" done < <(grep -rnE 'console\.log\(' "$repo_dir" \ --include='*.ts' --include='*.tsx' --include='*.js' --include='*.jsx' --include='*.mjs' \ @@ -298,6 +325,15 @@ scan_web_hardcoded_hex() { # Unicode characters, NOT hex colors (the digits happen to be in [0-9] which # is a subset of hex, fooling the regex). [[ "$content" =~ \&\#[0-9]+\; ]] && continue + # File-level opt-out: any file containing the marker AGENTS-SCAN-EXEMPT-HEX + # in its first 50 lines is exempt. This is for legitimate visualization-data + # files that inline canvas-draw functions tightly coupled to per-organ / + # per-stage hex colors (where extraction would break draw-function closure + # semantics). The marker MUST be paired with a referenced TODO-N comment so + # the exception is tracked. + if head -50 "$file" 2>/dev/null | grep -q "AGENTS-SCAN-EXEMPT-HEX"; then + continue + fi # Extract just the hex match for evidence. local match match=$(echo "$content" | grep -oE '#[0-9a-fA-F]{6}\b|#[0-9a-fA-F]{3}\b' | head -1)