Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0e9ddc3c57 |
+8
-14
@@ -3,25 +3,19 @@
|
|||||||
## Language & Dependencies
|
## Language & Dependencies
|
||||||
|
|
||||||
- Target the latest stable Go release.
|
- Target the latest stable Go release.
|
||||||
- **STRICT ALLOWLIST:** Only packages listed below may be imported. No exceptions.
|
- Prefer Go standard library; approved third-party packages allowed (see below).
|
||||||
|
|
||||||
### Approved Third-Party Packages
|
### Approved Third-Party Packages
|
||||||
|
|
||||||
| Package | Use Case | Scope |
|
| Package | Use Case | Notes |
|
||||||
|---------|----------|-------|
|
|---------|----------|-------|
|
||||||
| `gopkg.in/yaml.v3` | YAML parsing (persona files, config) | production |
|
| `gopkg.in/yaml.v3` | YAML parsing | Persona files, config |
|
||||||
| `github.com/google/go-cmp` | Test comparisons (`cmp.Diff`) | test only |
|
| `github.com/google/go-cmp` | Test comparisons | `cmp.Diff` for readable diffs |
|
||||||
|
|
||||||
**Any import not in this table or the Go standard library is forbidden.**
|
To add a new dependency:
|
||||||
|
1. Open a PR with justification (why stdlib is insufficient)
|
||||||
Only *direct* dependencies (listed in go.mod without `// indirect`) are checked against this allowlist. Transitive dependencies pulled in by approved packages are implicitly allowed.
|
2. Package must be well-maintained, widely used, minimal transitive deps
|
||||||
|
3. Update this table when approved
|
||||||
To request a new dependency:
|
|
||||||
1. Open a PR that ONLY updates this table
|
|
||||||
2. Requires explicit approval from Aaron
|
|
||||||
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
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
.PHONY: build test test-integration lint clean coverage check-deps precommit
|
.PHONY: build test test-integration lint clean coverage
|
||||||
|
|
||||||
build:
|
build:
|
||||||
go build -o review-bot ./cmd/review-bot/
|
go build -o review-bot ./cmd/review-bot/
|
||||||
@@ -12,15 +12,9 @@ test-integration:
|
|||||||
lint:
|
lint:
|
||||||
go vet ./...
|
go vet ./...
|
||||||
|
|
||||||
check-deps:
|
|
||||||
@./scripts/check-deps.sh
|
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f review-bot
|
rm -f review-bot
|
||||||
|
|
||||||
coverage:
|
coverage:
|
||||||
go test -coverprofile=coverage.out ./...
|
go test -coverprofile=coverage.out ./...
|
||||||
go tool cover -func=coverage.out
|
go tool cover -func=coverage.out
|
||||||
|
|
||||||
# Precommit runs all checks required before pushing
|
|
||||||
precommit: check-deps lint test
|
|
||||||
|
|||||||
@@ -1,133 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# check-deps.sh - Enforces the strict dependency allowlist from CONVENTIONS.md
|
|
||||||
# Exit 1 if any unapproved import is found.
|
|
||||||
#
|
|
||||||
# Requires: Bash 4+ (for associative arrays), Go toolchain
|
|
||||||
#
|
|
||||||
# The allowlist is parsed from CONVENTIONS.md to maintain a single source of truth.
|
|
||||||
# Enforces Scope column: "test only" packages cannot appear in non-test code.
|
|
||||||
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
# Check bash version
|
|
||||||
if ((BASH_VERSINFO[0] < 4)); then
|
|
||||||
echo "❌ Bash 4+ required (found ${BASH_VERSION})"
|
|
||||||
echo " On macOS: brew install bash"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
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
|
|
||||||
# Note: uses Bash process substitution (< <(...)) for the loop
|
|
||||||
# Format: | `package` | use case | scope |
|
|
||||||
declare -A ALLOWED_PROD=()
|
|
||||||
declare -A ALLOWED_TEST=()
|
|
||||||
|
|
||||||
while IFS= read -r line; do
|
|
||||||
# Use awk to extract package and scope from table row
|
|
||||||
pkg=$(echo "$line" | awk -F'|' '{gsub(/^[[:space:]]*`|`[[:space:]]*$/, "", $2); print $2}')
|
|
||||||
scope=$(echo "$line" | awk -F'|' '{gsub(/^[[:space:]]+|[[:space:]]+$/, "", $4); print tolower($4)}')
|
|
||||||
|
|
||||||
# Accept packages starting with letter or digit (e.g., 9fans.net/go)
|
|
||||||
if [ -n "$pkg" ] && [ "$pkg" != "Package" ] && [[ "$pkg" =~ ^[[:alnum:]] ]]; then
|
|
||||||
if [[ "$scope" == *"test"* ]]; then
|
|
||||||
ALLOWED_TEST["$pkg"]=1
|
|
||||||
else
|
|
||||||
ALLOWED_PROD["$pkg"]=1
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
done < <(grep '| `' "$CONVENTIONS_FILE" 2>/dev/null || true)
|
|
||||||
|
|
||||||
ALL_ALLOWED=("${!ALLOWED_PROD[@]}" "${!ALLOWED_TEST[@]}")
|
|
||||||
|
|
||||||
if [ ${#ALL_ALLOWED[@]} -eq 0 ]; then
|
|
||||||
echo "⚠️ No approved packages found in $CONVENTIONS_FILE"
|
|
||||||
echo " (This is fine if you want stdlib-only)"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Helper: check if import matches any package in an associative array (literal prefix, no glob)
|
|
||||||
matches_allowlist() {
|
|
||||||
local import="$1"
|
|
||||||
shift
|
|
||||||
local -n allowlist=$1
|
|
||||||
|
|
||||||
for allowed in "${!allowlist[@]}"; do
|
|
||||||
# Exact match
|
|
||||||
if [ "$import" = "$allowed" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
# Literal prefix match for subpackages: must match "pkg/" exactly
|
|
||||||
if [ "${import#"$allowed/"}" != "$import" ]; then
|
|
||||||
return 0
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
# Get direct module dependencies from go.mod
|
|
||||||
# Capture stderr separately to avoid mixing error messages with package list
|
|
||||||
GO_LIST_STDERR=$(mktemp)
|
|
||||||
trap 'rm -f "$GO_LIST_STDERR"' EXIT
|
|
||||||
DIRECT_IMPORTS=$(go list -m -f '{{if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all 2>"$GO_LIST_STDERR") || {
|
|
||||||
echo "❌ Failed to list dependencies:"
|
|
||||||
cat "$GO_LIST_STDERR"
|
|
||||||
exit 1
|
|
||||||
}
|
|
||||||
DIRECT_IMPORTS=$(echo "$DIRECT_IMPORTS" | grep -v '^$' || true)
|
|
||||||
|
|
||||||
if [ -z "$DIRECT_IMPORTS" ]; then
|
|
||||||
echo "✅ No external dependencies"
|
|
||||||
exit 0
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Check ALL direct dependencies are in some allowlist
|
|
||||||
VIOLATIONS=""
|
|
||||||
while IFS= read -r import; do
|
|
||||||
[ -z "$import" ] && continue
|
|
||||||
|
|
||||||
if ! matches_allowlist "$import" ALLOWED_PROD && ! matches_allowlist "$import" ALLOWED_TEST; then
|
|
||||||
VIOLATIONS="${VIOLATIONS} - ${import} (not in allowlist)"$'\n'
|
|
||||||
fi
|
|
||||||
done <<< "$DIRECT_IMPORTS"
|
|
||||||
|
|
||||||
if [ -n "$VIOLATIONS" ]; then
|
|
||||||
echo "❌ UNAPPROVED DEPENDENCIES DETECTED"
|
|
||||||
echo ""
|
|
||||||
echo "The following imports are not in the allowlist:"
|
|
||||||
printf "%s" "$VIOLATIONS"
|
|
||||||
echo ""
|
|
||||||
echo "To add a dependency, update CONVENTIONS.md (requires Aaron's approval)"
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Enforce Scope: test-only packages must not appear in non-test code
|
|
||||||
# Get imports used by non-test code only (go list -deps without -test excludes test deps)
|
|
||||||
PROD_IMPORTS=$(go list -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./... 2>/dev/null || true)
|
|
||||||
|
|
||||||
TEST_ONLY_IN_PROD=""
|
|
||||||
for test_pkg in "${!ALLOWED_TEST[@]}"; do
|
|
||||||
# Match exact package or subpackages (pkg or pkg/...)
|
|
||||||
if echo "$PROD_IMPORTS" | grep -qE "^${test_pkg}(/|$)"; then
|
|
||||||
TEST_ONLY_IN_PROD="${TEST_ONLY_IN_PROD} - ${test_pkg} (marked 'test only' but used in production code)"$'\n'
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ -n "$TEST_ONLY_IN_PROD" ]; then
|
|
||||||
echo "❌ TEST-ONLY DEPENDENCIES IN PRODUCTION CODE"
|
|
||||||
echo ""
|
|
||||||
printf "%s" "$TEST_ONLY_IN_PROD"
|
|
||||||
echo ""
|
|
||||||
echo "These packages are marked 'test only' in CONVENTIONS.md"
|
|
||||||
echo "and must only be imported from *_test.go files."
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "✅ All dependencies are approved"
|
|
||||||
echo " Direct module deps: $(echo "$DIRECT_IMPORTS" | wc -l | tr -d ' ')"
|
|
||||||
echo " Production allowlist: ${#ALLOWED_PROD[@]}, Test-only allowlist: ${#ALLOWED_TEST[@]}"
|
|
||||||
Reference in New Issue
Block a user