fix: address review feedback on dependency allowlist
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
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
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
This commit is contained in:
+9
-5
@@ -7,18 +7,22 @@
|
|||||||
|
|
||||||
### Approved Third-Party Packages
|
### Approved Third-Party Packages
|
||||||
|
|
||||||
| Package | Use Case |
|
| Package | Use Case | Scope |
|
||||||
|---------|----------|
|
|---------|----------|-------|
|
||||||
| `gopkg.in/yaml.v3` | YAML parsing (persona files, config) |
|
| `gopkg.in/yaml.v3` | YAML parsing (persona files, config) | production |
|
||||||
| `github.com/google/go-cmp` | Test comparisons (`cmp.Diff`) |
|
| `github.com/google/go-cmp` | Test comparisons (`cmp.Diff`) | test only |
|
||||||
|
|
||||||
**Any import not in this table or the Go standard library is forbidden.**
|
**Any import not in this table or the Go standard library is forbidden.**
|
||||||
|
|
||||||
|
Transitive dependencies of approved packages are automatically allowed.
|
||||||
|
|
||||||
To request a new dependency:
|
To request a new dependency:
|
||||||
1. Open a PR that ONLY updates this table with justification
|
1. Open a PR that ONLY updates this table
|
||||||
2. Requires explicit approval from Aaron
|
2. Requires explicit approval from Aaron
|
||||||
3. After merge, a separate PR may use the package
|
3. After merge, a separate PR may use the package
|
||||||
|
|
||||||
|
*Enforcement: `scripts/check-deps.sh` parses this table — update only here.*
|
||||||
|
|
||||||
## Error Handling
|
## Error Handling
|
||||||
|
|
||||||
- Return errors; never panic.
|
- Return errors; never panic.
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: build test test-integration lint clean coverage check-deps
|
.PHONY: build test test-integration lint clean coverage check-deps precommit
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build -o review-bot ./cmd/review-bot/
|
go build -o review-bot ./cmd/review-bot/
|
||||||
|
|||||||
+42
-19
@@ -1,27 +1,43 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
# check-deps.sh - Enforces the strict dependency allowlist from CONVENTIONS.md
|
# check-deps.sh - Enforces the strict dependency allowlist from CONVENTIONS.md
|
||||||
# Exit 1 if any unapproved import is found.
|
# 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
|
set -euo pipefail
|
||||||
|
|
||||||
# Approved third-party packages (from CONVENTIONS.md)
|
CONVENTIONS_FILE="${1:-CONVENTIONS.md}"
|
||||||
ALLOWED=(
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
"github.com/google/go-cmp"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Build regex pattern from allowed list
|
if [ ! -f "$CONVENTIONS_FILE" ]; then
|
||||||
ALLOWED_PATTERN=""
|
echo "❌ CONVENTIONS.md not found"
|
||||||
for pkg in "${ALLOWED[@]}"; do
|
exit 1
|
||||||
if [ -z "$ALLOWED_PATTERN" ]; then
|
fi
|
||||||
ALLOWED_PATTERN="$pkg"
|
|
||||||
else
|
# Parse approved packages from CONVENTIONS.md table
|
||||||
ALLOWED_PATTERN="$ALLOWED_PATTERN|$pkg"
|
# 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
|
fi
|
||||||
done
|
done < <(grep -E '^\| `[a-zA-Z]' "$CONVENTIONS_FILE" || true)
|
||||||
|
|
||||||
# Get all imports from go.mod (excluding the module itself and stdlib)
|
if [ ${#ALLOWED[@]} -eq 0 ]; then
|
||||||
IMPORTS=$(go list -m all 2>/dev/null | tail -n +2 | awk '{print $1}' || true)
|
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
|
if [ -z "$IMPORTS" ]; then
|
||||||
echo "✅ No external dependencies"
|
echo "✅ No external dependencies"
|
||||||
@@ -30,10 +46,9 @@ fi
|
|||||||
|
|
||||||
VIOLATIONS=""
|
VIOLATIONS=""
|
||||||
while IFS= read -r import; do
|
while IFS= read -r import; do
|
||||||
# Skip empty lines
|
|
||||||
[ -z "$import" ] && continue
|
[ -z "$import" ] && continue
|
||||||
|
|
||||||
# Check if import matches any allowed pattern (prefix match for subpackages)
|
# Check if import matches any allowed package (prefix match for subpackages)
|
||||||
MATCHED=false
|
MATCHED=false
|
||||||
for allowed in "${ALLOWED[@]}"; do
|
for allowed in "${ALLOWED[@]}"; do
|
||||||
if [[ "$import" == "$allowed" ]] || [[ "$import" == "$allowed/"* ]]; then
|
if [[ "$import" == "$allowed" ]] || [[ "$import" == "$allowed/"* ]]; then
|
||||||
@@ -43,13 +58,20 @@ while IFS= read -r import; do
|
|||||||
done
|
done
|
||||||
|
|
||||||
if [ "$MATCHED" = false ]; then
|
if [ "$MATCHED" = false ]; then
|
||||||
VIOLATIONS="$VIOLATIONS\n - $import"
|
VIOLATIONS="${VIOLATIONS} - ${import}"$'\n'
|
||||||
fi
|
fi
|
||||||
done <<< "$IMPORTS"
|
done <<< "$IMPORTS"
|
||||||
|
|
||||||
if [ -n "$VIOLATIONS" ]; then
|
if [ -n "$VIOLATIONS" ]; then
|
||||||
echo "❌ UNAPPROVED DEPENDENCIES DETECTED"
|
echo "❌ UNAPPROVED DEPENDENCIES DETECTED"
|
||||||
echo -e "The following imports are not in the allowlist:$VIOLATIONS"
|
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 ""
|
||||||
echo "To add a dependency:"
|
echo "To add a dependency:"
|
||||||
echo " 1. Open a PR that ONLY updates CONVENTIONS.md"
|
echo " 1. Open a PR that ONLY updates CONVENTIONS.md"
|
||||||
@@ -59,3 +81,4 @@ if [ -n "$VIOLATIONS" ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "✅ All dependencies are approved"
|
echo "✅ All dependencies are approved"
|
||||||
|
echo " Direct deps: $(echo "$IMPORTS" | wc -l | tr -d ' ')"
|
||||||
|
|||||||
Reference in New Issue
Block a user