Files
deusdata--codebase-memory-mcp/scripts/audit-grammar-security.sh
test b2b48f8b0d Add 89 new tree-sitter grammars (66 to 155 languages)
Vendor, wire up, and compile 89 new tree-sitter grammars, expanding
language support from 66 to 155 languages. All grammars pass security
audit (no dangerous patterns in scanner.c files).

New programming languages (31):
  Solidity, Typst, GDScript, Gleam, PowerShell, Pascal, D, Nim, Scheme,
  Fennel, Fish, AWK, Zsh, Tcl, Ada, Agda, Racket, Odin, ReScript,
  PureScript, Nickel, Crystal, Teal, Hare, Pony, Luau, Janet, Sway,
  NASM, Assembly, TLA+, Pkl, Cairo, Move, Squirrel, ISPC, FunC, Smali

New config/data/IDL formats (31):
  Just, Astro, Blade, Go Template, Templ, Liquid, Jinja2, Prisma,
  Hyprlang, DotEnv, Diff, WGSL, KDL, JSON5, Jsonnet, RON, Thrift,
  Cap'n Proto, Properties, SSH Config, BibTeX, Starlark, Bicep, CSV,
  Requirements, HLSL, VHDL, SystemVerilog, DeviceTree, Linker Script,
  GN, Kconfig, BitBake, TableGen, Slang, LLVM IR, Smithy, WIT,
  Go Mod, Mermaid, RST, Beancount, Puppet, PO, Regex, JSDoc,
  gitattributes, gitignore, Apex, SOQL, SOSL

Infrastructure:
  - scripts/new-languages.json: manifest for all new languages
  - scripts/generate-lang-code.py: generates boilerplate from manifest
  - scripts/audit-grammar-security.sh: pre-vendoring security scanner
  - Fixed angle-bracket includes in 18 grammars
  - Fixed PureScript scanner const mismatch
  - Fixed VHDL scanner void* API signatures
  - Fixed RST tree_sitter_rst/ subdirectory include paths
  - Copied crystal unicode.c (extra scanner dependency)

All new languages start with minimal lang specs (module_types only).
Function/class/call extraction specs to be refined incrementally.
2026-04-15 21:28:51 +02:00

117 lines
4.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# audit-grammar-security.sh — Scan vendored tree-sitter grammar scanner.c
# files for dangerous patterns that could indicate malicious code.
#
# Grammars are third-party C source compiled into our binary. parser.c files
# are auto-generated (low risk), but scanner.c files are hand-written C with
# access to memory allocation and input text.
#
# Usage: scripts/audit-grammar-security.sh [directory]
# Default: internal/cbm/vendored/grammars/
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
GRAMMAR_DIR="${1:-$ROOT/internal/cbm/vendored/grammars}"
if [ ! -d "$GRAMMAR_DIR" ]; then
echo "ERROR: directory not found: $GRAMMAR_DIR" >&2
exit 1
fi
echo "=== Grammar Security Audit ==="
echo "Scanning: $GRAMMAR_DIR"
echo ""
TOTAL=0
WARNED=0
BLOCKED=0
# Safe includes that scanners legitimately use
SAFE_INCLUDES='string\.h|stdint\.h|stdbool\.h|stdlib\.h|wctype\.h|stdio\.h|stddef\.h|limits\.h|assert\.h|ctype\.h|wchar\.h|math\.h|stdalign\.h|stdarg\.h|float\.h|inttypes\.h'
# Dangerous includes
DANGER_INCLUDES='unistd\.h|sys/|netdb\.h|dlfcn\.h|signal\.h|spawn\.h|pthread\.h|fcntl\.h|dirent\.h|termios\.h|arpa/|netinet/'
# Dangerous function calls (word-boundary \b to avoid matching lex_accept, etc.)
# getenv("TREE_SITTER_DEBUG") is a standard tree-sitter pattern, excluded.
DANGER_CALLS='\bsystem\s*\(|\bexec[lvpe]+\s*\(|\bpopen\s*\(|\bfopen\s*\(|\bfwrite\s*\(|\bsocket\s*\(|\bfork\s*\(|\bdlopen\s*\(|\bconnect\s*\(|\bbind\s*\(|\blisten\s*\(|\bsendto\s*\(|\brecvfrom\s*\(|\bmmap\s*\(|\bmprotect\s*\('
# getenv is only dangerous for non-debug uses
DANGER_GETENV='\bgetenv\s*\('
SAFE_GETENV='TREE_SITTER_DEBUG'
# Suspicious patterns
SUSPICIOUS='__attribute__\s*\(\s*\(\s*constructor|__attribute__\s*\(\s*\(\s*destructor|asm\s*\(|__asm__|__asm\b'
for grammar_dir in "$GRAMMAR_DIR"/*/; do
name=$(basename "$grammar_dir")
TOTAL=$((TOTAL + 1))
issues=""
for src in "$grammar_dir"scanner.c "$grammar_dir"scanner.cc "$grammar_dir"*.h "$grammar_dir"*.inc; do
[ -f "$src" ] || continue
basename_src=$(basename "$src")
# Skip tree_sitter/ subdirectory headers (those are standard)
case "$src" in
*/tree_sitter/*) continue ;;
esac
# Check dangerous includes
while IFS= read -r line; do
issues="${issues} WARN $basename_src: dangerous include: $line\n"
done < <(grep -nE "#include\s*<($DANGER_INCLUDES)" "$src" 2>/dev/null || true)
# Check dangerous calls
while IFS= read -r line; do
issues="${issues} BLOCK $basename_src: dangerous call: $line\n"
done < <(grep -nE "$DANGER_CALLS" "$src" 2>/dev/null || true)
# Check getenv separately (allow TREE_SITTER_DEBUG)
while IFS= read -r line; do
if ! echo "$line" | grep -qF "$SAFE_GETENV"; then
issues="${issues} BLOCK $basename_src: dangerous call: $line\n"
fi
done < <(grep -nE "$DANGER_GETENV" "$src" 2>/dev/null || true)
# Check suspicious patterns
while IFS= read -r line; do
issues="${issues} BLOCK $basename_src: suspicious pattern: $line\n"
done < <(grep -nE "$SUSPICIOUS" "$src" 2>/dev/null || true)
# Check for base64-like long encoded strings (40+ alphanumeric chars)
while IFS= read -r line; do
issues="${issues} WARN $basename_src: possible encoded data: $line\n"
done < <(grep -nE '"[A-Za-z0-9+/]{60,}={0,2}"' "$src" 2>/dev/null || true)
done
if [ -n "$issues" ]; then
if echo -e "$issues" | grep -q "BLOCK"; then
echo "BLOCK $name:"
echo -e "$issues"
BLOCKED=$((BLOCKED + 1))
else
echo "WARN $name:"
echo -e "$issues"
WARNED=$((WARNED + 1))
fi
fi
done
echo "────────────────────────────────────────────"
echo " Scanned: $TOTAL grammars"
echo " Clean: $((TOTAL - WARNED - BLOCKED))"
echo " Warned: $WARNED"
echo " Blocked: $BLOCKED"
echo "────────────────────────────────────────────"
if [ "$BLOCKED" -gt 0 ]; then
echo ""
echo "FAILED: $BLOCKED grammar(s) have dangerous patterns. Review before vendoring."
exit 1
fi
echo ""
echo "PASSED: No dangerous patterns found."
exit 0