Files
review-bot/scripts/check-deps.sh
T
Rodin 70267b68f4
PR Ready Gate / clear-labels (pull_request) Successful in 2s
CI / test (pull_request) Successful in 14s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 32s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m27s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m28s
fix: address review feedback on dependency allowlist
Fixes:
- Single source of truth: script now parses allowlist from CONVENTIONS.md
- Fail closed: script exits non-zero if 'go list' fails
- Direct deps only: uses '-f' flag to exclude transitive deps
- Added 'precommit' to .PHONY in Makefile
- Removed unused ALLOWED_PATTERN variable
- Added Scope column to distinguish test-only vs production deps
- Clarified that transitive deps of approved packages are allowed
- Added note that enforcement script parses the table
2026-05-10 13:53:55 -07:00

85 lines
2.5 KiB
Bash
Executable File

#!/bin/bash
# check-deps.sh - Enforces the strict dependency allowlist from CONVENTIONS.md
# Exit 1 if any unapproved import is found.
#
# The allowlist is parsed from CONVENTIONS.md to maintain a single source of truth.
set -euo pipefail
CONVENTIONS_FILE="${1:-CONVENTIONS.md}"
if [ ! -f "$CONVENTIONS_FILE" ]; then
echo "❌ CONVENTIONS.md not found"
exit 1
fi
# Parse approved packages from CONVENTIONS.md table
# Looks for lines like: | `gopkg.in/yaml.v3` | ...
ALLOWED=()
while IFS= read -r line; do
# Extract package from markdown table cell: | `package` |
pkg=$(echo "$line" | grep -oP '\| `\K[^`]+' | head -1 || true)
if [ -n "$pkg" ] && [[ "$pkg" != "Package" ]]; then
ALLOWED+=("$pkg")
fi
done < <(grep -E '^\| `[a-zA-Z]' "$CONVENTIONS_FILE" || true)
if [ ${#ALLOWED[@]} -eq 0 ]; then
echo "⚠️ No approved packages found in $CONVENTIONS_FILE"
echo " (This is fine if you want stdlib-only)"
fi
# Get DIRECT dependencies only (exclude indirect/transitive)
# Fail closed: if go list fails, we exit non-zero
IMPORTS=$(go list -m -f '{{if not .Indirect}}{{.Path}}{{end}}' all 2>&1) || {
echo "❌ Failed to list dependencies: $IMPORTS"
exit 1
}
# Filter out the module itself (first line) and empty lines
IMPORTS=$(echo "$IMPORTS" | tail -n +2 | grep -v '^$' || true)
if [ -z "$IMPORTS" ]; then
echo "✅ No external dependencies"
exit 0
fi
VIOLATIONS=""
while IFS= read -r import; do
[ -z "$import" ] && continue
# Check if import matches any allowed package (prefix match for subpackages)
MATCHED=false
for allowed in "${ALLOWED[@]}"; do
if [[ "$import" == "$allowed" ]] || [[ "$import" == "$allowed/"* ]]; then
MATCHED=true
break
fi
done
if [ "$MATCHED" = false ]; then
VIOLATIONS="${VIOLATIONS} - ${import}"$'\n'
fi
done <<< "$IMPORTS"
if [ -n "$VIOLATIONS" ]; then
echo "❌ UNAPPROVED DEPENDENCIES DETECTED"
echo ""
echo "The following imports are not in the allowlist:"
printf "%s" "$VIOLATIONS"
echo ""
echo "Approved packages (from CONVENTIONS.md):"
for pkg in "${ALLOWED[@]}"; do
echo " - $pkg"
done
echo ""
echo "To add a dependency:"
echo " 1. Open a PR that ONLY updates CONVENTIONS.md"
echo " 2. Get explicit approval from Aaron"
echo " 3. After merge, use the package in a separate PR"
exit 1
fi
echo "✅ All dependencies are approved"
echo " Direct deps: $(echo "$IMPORTS" | wc -l | tr -d ' ')"