#!/usr/bin/env bash set -euo pipefail RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' NC='\033[0m' TARGET="${1:-.}" errors=0 echo "=== SAST Scan ===" if ! command -v semgrep &>/dev/null; then printf "${RED}✗${NC} semgrep not installed\n" exit 2 fi # Probe for source files. Explicit prunes (rather than -not -path "*/.*") # so that target paths under hidden ancestor dirs (e.g. a Claude Code # worktree at .../.claude/worktrees//) still match real source. # -print -quit instead of `| head -1` avoids SIGPIPE under `set -o pipefail`. has_python=$(find "$TARGET" \ \( -path '*/__pycache__' -o -path '*/.venv' -o -path '*/venv' \ -o -path '*/.git' -o -path '*/node_modules' \) -prune \ -o -name '*.py' -print -quit) has_go=$(find "$TARGET" \ \( -path '*/.git' -o -path '*/vendor' -o -path '*/node_modules' \) -prune \ -o -name '*.go' -print -quit) if [ -z "$has_python" ] && [ -z "$has_go" ]; then printf "${YELLOW}!${NC} No Python or Go files found — skipping\n" exit 0 fi configs="" if [ -n "$has_python" ]; then configs="--config=p/python --config=p/owasp-top-ten" fi if [ -n "$has_go" ]; then configs="$configs --config=p/golang --config=p/owasp-top-ten" fi if semgrep scan $configs "$TARGET" --quiet 2>/dev/null; then printf "${GREEN}✓${NC} No security issues found\n" exit 0 else printf "${RED}✗${NC} Security issues detected — review semgrep output above\n" exit 1 fi