docs: allow approved third-party packages #59

Merged
rodin merged 4 commits from allow-deps into main 2026-05-10 21:07:10 +00:00
Owner

Updates dependency policy from "stdlib only" to "stdlib preferred, approved packages allowed".

Changes

  • Adds approved third-party packages table to CONVENTIONS.md
  • Initial approved list:
    • gopkg.in/yaml.v3 — YAML parsing for persona files
    • github.com/google/go-cmp — Test comparisons with readable diffs
  • Documents process for adding new dependencies

Why

The "stdlib only" policy was too restrictive for practical development. Some tasks (YAML parsing, test comparisons) are better served by battle-tested packages than rolling our own.

This unblocks PR #58 (YAML persona support).

Updates dependency policy from "stdlib only" to "stdlib preferred, approved packages allowed". ## Changes - Adds approved third-party packages table to CONVENTIONS.md - Initial approved list: - `gopkg.in/yaml.v3` — YAML parsing for persona files - `github.com/google/go-cmp` — Test comparisons with readable diffs - Documents process for adding new dependencies ## Why The "stdlib only" policy was too restrictive for practical development. Some tasks (YAML parsing, test comparisons) are better served by battle-tested packages than rolling our own. This unblocks PR #58 (YAML persona support).
rodin self-assigned this 2026-05-10 20:44:11 +00:00
sonnet-review-bot approved these changes 2026-05-10 20:44:52 +00:00
sonnet-review-bot left a comment
First-time contributor

Original review

Supersededsee current review for up-to-date findings.

Previous findings (commit 0e9ddc3c)

Sonnet Review

Summary

This PR updates the dependency policy in CONVENTIONS.md from 'stdlib only' to 'stdlib preferred with approved packages', adding gopkg.in/yaml.v3 and github.com/google/go-cmp to an initial approved list. The change is purely documentation, CI passed, and the process described is reasonable.

Findings

# Severity File Line Finding
1 [NIT] CONVENTIONS.md 12 go-cmp is a test-only dependency, but the table doesn't distinguish test dependencies from production dependencies. A 'Scope' column (e.g. 'test only' vs 'production') would clarify that go-cmp should never appear in non-test code, preventing accidental production use.
2 [NIT] CONVENTIONS.md 15 The process for adding new dependencies doesn't mention who has approval authority (e.g. maintainers, a specific review process). Adding a brief note like 'requires approval from a maintainer' would make the governance expectation explicit.

Recommendation

APPROVE — Approve. The change is well-scoped documentation update with a clear rationale. Both approved packages are widely used and well-maintained: gopkg.in/yaml.v3 is the canonical Go YAML library and go-cmp is the Google-maintained test comparison library used throughout the Go ecosystem. The process table and approval criteria are reasonable. The two nits (test-vs-production scope distinction, approval authority) are minor polish items that could be addressed in a follow-up if desired.


Review by sonnet


Evaluated against 0e9ddc3c

~~Original review~~ **Superseded** — [see current review](https://gitea.weiker.me/rodin/review-bot/pulls/59#pullrequestreview-2153) for up-to-date findings. <details><summary>Previous findings (commit 0e9ddc3c)</summary> # Sonnet Review ## Summary This PR updates the dependency policy in CONVENTIONS.md from 'stdlib only' to 'stdlib preferred with approved packages', adding `gopkg.in/yaml.v3` and `github.com/google/go-cmp` to an initial approved list. The change is purely documentation, CI passed, and the process described is reasonable. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [NIT] | `CONVENTIONS.md` | 12 | `go-cmp` is a test-only dependency, but the table doesn't distinguish test dependencies from production dependencies. A 'Scope' column (e.g. 'test only' vs 'production') would clarify that `go-cmp` should never appear in non-test code, preventing accidental production use. | | 2 | [NIT] | `CONVENTIONS.md` | 15 | The process for adding new dependencies doesn't mention who has approval authority (e.g. maintainers, a specific review process). Adding a brief note like 'requires approval from a maintainer' would make the governance expectation explicit. | ## Recommendation **APPROVE** — Approve. The change is well-scoped documentation update with a clear rationale. Both approved packages are widely used and well-maintained: `gopkg.in/yaml.v3` is the canonical Go YAML library and `go-cmp` is the Google-maintained test comparison library used throughout the Go ecosystem. The process table and approval criteria are reasonable. The two nits (test-vs-production scope distinction, approval authority) are minor polish items that could be addressed in a follow-up if desired. --- *Review by sonnet* <!-- review-bot:sonnet --> --- *Evaluated against 0e9ddc3c* </details> <!-- review-bot:sonnet -->
CONVENTIONS.md Outdated
@@ -7,0 +9,4 @@
| Package | Use Case | Notes |
|---------|----------|-------|
| `gopkg.in/yaml.v3` | YAML parsing | Persona files, config |
First-time contributor

[NIT] go-cmp is a test-only dependency, but the table doesn't distinguish test dependencies from production dependencies. A 'Scope' column (e.g. 'test only' vs 'production') would clarify that go-cmp should never appear in non-test code, preventing accidental production use.

**[NIT]** `go-cmp` is a test-only dependency, but the table doesn't distinguish test dependencies from production dependencies. A 'Scope' column (e.g. 'test only' vs 'production') would clarify that `go-cmp` should never appear in non-test code, preventing accidental production use.
CONVENTIONS.md Outdated
@@ -7,0 +12,4 @@
| `gopkg.in/yaml.v3` | YAML parsing | Persona files, config |
| `github.com/google/go-cmp` | Test comparisons | `cmp.Diff` for readable diffs |
To add a new dependency:
First-time contributor

[NIT] The process for adding new dependencies doesn't mention who has approval authority (e.g. maintainers, a specific review process). Adding a brief note like 'requires approval from a maintainer' would make the governance expectation explicit.

**[NIT]** The process for adding new dependencies doesn't mention who has approval authority (e.g. maintainers, a specific review process). Adding a brief note like 'requires approval from a maintainer' would make the governance expectation explicit.
rodin added 1 commit 2026-05-10 20:45:14 +00:00
docs: strict dependency allowlist with CI enforcement
PR Ready Gate / clear-labels (pull_request) Successful in 2s
CI / test (pull_request) Successful in 15s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 28s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m40s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m48s
4b96231b32
STRICT ALLOWLIST policy: Only packages explicitly listed in CONVENTIONS.md
may be imported. No exceptions.

## Changes

- Updates CONVENTIONS.md with strict allowlist language
- Adds scripts/check-deps.sh to enforce the allowlist
- Adds 'make check-deps' and 'make precommit' targets
- CI will fail if any unapproved dependency is detected

## Approved packages

- gopkg.in/yaml.v3 — YAML parsing
- github.com/google/go-cmp — test comparisons

## Process for new dependencies

1. Open a PR that ONLY updates CONVENTIONS.md
2. Requires explicit approval from Aaron
3. After merge, a separate PR may use the package
rodin force-pushed allow-deps from 0e9ddc3c57 to 4b96231b32 2026-05-10 20:45:14 +00:00 Compare
sonnet-review-bot approved these changes 2026-05-10 20:45:57 +00:00
sonnet-review-bot left a comment
First-time contributor

Original review

Supersededsee current review for up-to-date findings.

Previous findings (commit 4b96231b)

Sonnet Review

Summary

This PR updates the dependency policy from 'stdlib only' to a strict allowlist approach, adds two approved packages (yaml.v3 and go-cmp), and introduces enforcement tooling via a shell script and Makefile target. CI passed. The changes are well-structured and the enforcement mechanism is sound.

Findings

# Severity File Line Finding
1 [MINOR] scripts/check-deps.sh 14 The ALLOWED_PATTERN variable is built but never used. The actual checking is done in the loop with direct string comparison against the ALLOWED array. The dead code is harmless but confusing — either use the pattern (e.g., with grep) or remove it.
2 [MINOR] scripts/check-deps.sh 27 go list -m all includes indirect/transitive dependencies. If yaml.v3 or go-cmp pull in their own transitive deps, those would appear here and trigger false-positive violations. Consider using `go mod edit -json
3 [NIT] scripts/check-deps.sh 51 echo -e is not POSIX-compliant and behavior varies across shells (e.g., on some systems /bin/bash may not support -e with printf semantics). The \n in the violations string also won't render on all platforms. Consider using printf instead: printf 'The following imports are not in the allowlist:%b\n' "$VIOLATIONS".

Recommendation

APPROVE — Approve with minor notes. The policy change is clear, well-documented, and enforced via tooling. The two approved packages (yaml.v3 and go-cmp) are well-chosen battle-tested packages for their respective use cases. The dead ALLOWED_PATTERN variable and the transitive-dependency issue in the shell script are worth fixing in a follow-up, but they don't block this documentation/process PR. The transitive dependency issue in particular could cause noise once yaml.v3 or go-cmp are actually added to go.mod, so it's worth addressing before that happens.


Review by sonnet


Evaluated against 4b96231b

~~Original review~~ **Superseded** — [see current review](https://gitea.weiker.me/rodin/review-bot/pulls/59#pullrequestreview-2157) for up-to-date findings. <details><summary>Previous findings (commit 4b96231b)</summary> # Sonnet Review ## Summary This PR updates the dependency policy from 'stdlib only' to a strict allowlist approach, adds two approved packages (yaml.v3 and go-cmp), and introduces enforcement tooling via a shell script and Makefile target. CI passed. The changes are well-structured and the enforcement mechanism is sound. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MINOR] | `scripts/check-deps.sh` | 14 | The ALLOWED_PATTERN variable is built but never used. The actual checking is done in the loop with direct string comparison against the ALLOWED array. The dead code is harmless but confusing — either use the pattern (e.g., with grep) or remove it. | | 2 | [MINOR] | `scripts/check-deps.sh` | 27 | `go list -m all` includes indirect/transitive dependencies. If yaml.v3 or go-cmp pull in their own transitive deps, those would appear here and trigger false-positive violations. Consider using `go mod edit -json | jq '.Require[] | select(.Indirect == false) | .Path'` or filtering with `go list -m -mod=mod -f '{{if not .Indirect}}{{.Path}}{{end}}' all` to check only direct dependencies. | | 3 | [NIT] | `scripts/check-deps.sh` | 51 | `echo -e` is not POSIX-compliant and behavior varies across shells (e.g., on some systems /bin/bash may not support -e with printf semantics). The `\n` in the violations string also won't render on all platforms. Consider using `printf` instead: `printf 'The following imports are not in the allowlist:%b\n' "$VIOLATIONS"`. | ## Recommendation **APPROVE** — Approve with minor notes. The policy change is clear, well-documented, and enforced via tooling. The two approved packages (yaml.v3 and go-cmp) are well-chosen battle-tested packages for their respective use cases. The dead ALLOWED_PATTERN variable and the transitive-dependency issue in the shell script are worth fixing in a follow-up, but they don't block this documentation/process PR. The transitive dependency issue in particular could cause noise once yaml.v3 or go-cmp are actually added to go.mod, so it's worth addressing before that happens. --- *Review by sonnet* <!-- review-bot:sonnet --> --- *Evaluated against 4b96231b* </details> <!-- review-bot:sonnet -->
@@ -0,0 +11,4 @@
)
# Build regex pattern from allowed list
ALLOWED_PATTERN=""
First-time contributor

[MINOR] The ALLOWED_PATTERN variable is built but never used. The actual checking is done in the loop with direct string comparison against the ALLOWED array. The dead code is harmless but confusing — either use the pattern (e.g., with grep) or remove it.

**[MINOR]** The ALLOWED_PATTERN variable is built but never used. The actual checking is done in the loop with direct string comparison against the ALLOWED array. The dead code is harmless but confusing — either use the pattern (e.g., with grep) or remove it.
@@ -0,0 +24,4 @@
IMPORTS=$(go list -m all 2>/dev/null | tail -n +2 | awk '{print $1}' || true)
if [ -z "$IMPORTS" ]; then
echo "✅ No external dependencies"
First-time contributor

[MINOR] go list -m all includes indirect/transitive dependencies. If yaml.v3 or go-cmp pull in their own transitive deps, those would appear here and trigger false-positive violations. Consider using go mod edit -json | jq '.Require[] | select(.Indirect == false) | .Path' or filtering with go list -m -mod=mod -f '{{if not .Indirect}}{{.Path}}{{end}}' all to check only direct dependencies.

**[MINOR]** `go list -m all` includes indirect/transitive dependencies. If yaml.v3 or go-cmp pull in their own transitive deps, those would appear here and trigger false-positive violations. Consider using `go mod edit -json | jq '.Require[] | select(.Indirect == false) | .Path'` or filtering with `go list -m -mod=mod -f '{{if not .Indirect}}{{.Path}}{{end}}' all` to check only direct dependencies.
@@ -0,0 +48,4 @@
done <<< "$IMPORTS"
if [ -n "$VIOLATIONS" ]; then
echo "❌ UNAPPROVED DEPENDENCIES DETECTED"
First-time contributor

[NIT] echo -e is not POSIX-compliant and behavior varies across shells (e.g., on some systems /bin/bash may not support -e with printf semantics). The \n in the violations string also won't render on all platforms. Consider using printf instead: printf 'The following imports are not in the allowlist:%b\n' "$VIOLATIONS".

**[NIT]** `echo -e` is not POSIX-compliant and behavior varies across shells (e.g., on some systems /bin/bash may not support -e with printf semantics). The `\n` in the violations string also won't render on all platforms. Consider using `printf` instead: `printf 'The following imports are not in the allowlist:%b\n' "$VIOLATIONS"`.
security-review-bot requested review from security-review-bot 2026-05-10 20:47:10 +00:00
security-review-bot approved these changes 2026-05-10 20:47:10 +00:00
Dismissed
security-review-bot left a comment
Collaborator

Security Review

Summary

The changes introduce a strict dependency allowlist with an enforcement script and hook it into the build workflow. Overall this improves supply-chain security. I found minor hardening opportunities in the enforcement script and CI integration but no exploitable vulnerabilities.

Findings

# Severity File Line Finding
1 [MINOR] scripts/check-deps.sh 24 The script fails open if go list -m all errors (`
2 [MINOR] Makefile 26 The new precommit target runs the dependency check, but unless CI invokes this target, policy enforcement may not occur in CI. Ensure CI runs make precommit (or otherwise invokes check-deps) to prevent unapproved dependencies from being merged.
3 [MINOR] scripts/check-deps.sh 8 The allowlist is duplicated between CONVENTIONS.md and this script (ALLOWED array), creating a risk of drift. A mismatch could either block approved deps or unintentionally allow unapproved ones, weakening policy enforcement. Consider deriving the list from a single source (e.g., parse CONVENTIONS.md or define the list in a single machine-readable file).

Recommendation

APPROVE — Overall the policy and automation are a net security improvement and CI has passed, so this can be merged. To strengthen enforcement, update scripts/check-deps.sh to fail closed when go list -m all fails (e.g., remove || true and treat command failure as an error), and ensure your CI pipeline invokes make precommit so check-deps runs on every PR. To avoid policy drift, keep the allowlist in a single source of truth that both documentation and the script consume (e.g., a JSON/YAML file or by parsing the markdown table). These changes will make the dependency policy more robust against supply-chain risks.


Review by security


Evaluated against 4b96231b

# Security Review ## Summary The changes introduce a strict dependency allowlist with an enforcement script and hook it into the build workflow. Overall this improves supply-chain security. I found minor hardening opportunities in the enforcement script and CI integration but no exploitable vulnerabilities. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MINOR] | `scripts/check-deps.sh` | 24 | The script fails open if `go list -m all` errors (`|| true`), then treats an empty IMPORTS as "no external dependencies" and exits 0. This can bypass enforcement if the Go toolchain is unavailable or the command fails. Prefer failing closed on errors or explicitly erroring when `go list` fails. | | 2 | [MINOR] | `Makefile` | 26 | The new `precommit` target runs the dependency check, but unless CI invokes this target, policy enforcement may not occur in CI. Ensure CI runs `make precommit` (or otherwise invokes `check-deps`) to prevent unapproved dependencies from being merged. | | 3 | [MINOR] | `scripts/check-deps.sh` | 8 | The allowlist is duplicated between CONVENTIONS.md and this script (`ALLOWED` array), creating a risk of drift. A mismatch could either block approved deps or unintentionally allow unapproved ones, weakening policy enforcement. Consider deriving the list from a single source (e.g., parse CONVENTIONS.md or define the list in a single machine-readable file). | ## Recommendation **APPROVE** — Overall the policy and automation are a net security improvement and CI has passed, so this can be merged. To strengthen enforcement, update scripts/check-deps.sh to fail closed when `go list -m all` fails (e.g., remove `|| true` and treat command failure as an error), and ensure your CI pipeline invokes `make precommit` so `check-deps` runs on every PR. To avoid policy drift, keep the allowlist in a single source of truth that both documentation and the script consume (e.g., a JSON/YAML file or by parsing the markdown table). These changes will make the dependency policy more robust against supply-chain risks. --- *Review by security* <!-- review-bot:security --> --- *Evaluated against 4b96231b*
@@ -20,1 +23,4 @@
go tool cover -func=coverage.out
# Precommit runs all checks required before pushing
precommit: check-deps lint test
Collaborator

[MINOR] The new precommit target runs the dependency check, but unless CI invokes this target, policy enforcement may not occur in CI. Ensure CI runs make precommit (or otherwise invokes check-deps) to prevent unapproved dependencies from being merged.

**[MINOR]** The new `precommit` target runs the dependency check, but unless CI invokes this target, policy enforcement may not occur in CI. Ensure CI runs `make precommit` (or otherwise invokes `check-deps`) to prevent unapproved dependencies from being merged.
@@ -0,0 +5,4 @@
set -euo pipefail
# Approved third-party packages (from CONVENTIONS.md)
ALLOWED=(
Collaborator

[MINOR] The allowlist is duplicated between CONVENTIONS.md and this script (ALLOWED array), creating a risk of drift. A mismatch could either block approved deps or unintentionally allow unapproved ones, weakening policy enforcement. Consider deriving the list from a single source (e.g., parse CONVENTIONS.md or define the list in a single machine-readable file).

**[MINOR]** The allowlist is duplicated between CONVENTIONS.md and this script (`ALLOWED` array), creating a risk of drift. A mismatch could either block approved deps or unintentionally allow unapproved ones, weakening policy enforcement. Consider deriving the list from a single source (e.g., parse CONVENTIONS.md or define the list in a single machine-readable file).
@@ -0,0 +21,4 @@
done
# Get all imports from go.mod (excluding the module itself and stdlib)
IMPORTS=$(go list -m all 2>/dev/null | tail -n +2 | awk '{print $1}' || true)
Collaborator

[MINOR] The script fails open if go list -m all errors (|| true), then treats an empty IMPORTS as "no external dependencies" and exits 0. This can bypass enforcement if the Go toolchain is unavailable or the command fails. Prefer failing closed on errors or explicitly erroring when go list fails.

**[MINOR]** The script fails open if `go list -m all` errors (`|| true`), then treats an empty IMPORTS as "no external dependencies" and exits 0. This can bypass enforcement if the Go toolchain is unavailable or the command fails. Prefer failing closed on errors or explicitly erroring when `go list` fails.
gpt-review-bot requested changes 2026-05-10 20:47:17 +00:00
gpt-review-bot left a comment
First-time contributor

Original review

Supersededsee current review for up-to-date findings.

Previous findings (commit 4b96231b)

Gpt Review

Summary

Good step toward a controlled allowlist-based dependency policy and automated enforcement. However, the enforcement script hard-codes the allowlist, which diverges from the documented process and can cause drift; also a couple of minor Makefile/script nits.

Findings

# Severity File Line Finding
1 [MAJOR] scripts/check-deps.sh 8 The allowlist is hard-coded in the script (ALLOWED array) while CONVENTIONS.md is presented as the source of truth. The documented process says to open a PR that ONLY updates the table, but the enforcement will still fail later unless this script is updated too. This mismatch will cause policy drift and block subsequent PRs using newly approved dependencies.
2 [MINOR] CONVENTIONS.md 13 The dependency request process omits updating the enforcement mechanism. If the allowlist remains hard-coded in scripts/check-deps.sh, instructions should explicitly require updating the script alongside the table, or the script should be changed to derive its allowlist from a single canonical source.
3 [MINOR] Makefile 1 The new 'precommit' target isn't listed in .PHONY. It should be added to avoid make treating a file named 'precommit' as up-to-date and skipping the target.
4 [NIT] scripts/check-deps.sh 15 ALLOWED_PATTERN is built but never used. Remove this dead code to reduce confusion and keep the script minimal.
5 [MINOR] CONVENTIONS.md 11 Policy text says 'Only packages listed below may be imported' but the enforcement checks modules via 'go list -m all' and will also block any transitive modules not on the list. Consider clarifying that approving a dependency may entail approving its transitive modules, or adjust the script to allow transitive deps of approved modules automatically.

Recommendation

REQUEST_CHANGES — The policy change and automation are sensible, but the allowlist must have a single source of truth to avoid drift with the documented process. Please either (a) teach scripts/check-deps.sh to parse the allowlist from CONVENTIONS.md (or a separate machine-readable allowlist file that CONVENTIONS.md references), or (b) update CONVENTIONS.md to explicitly require updating scripts/check-deps.sh in the same PR that updates the table. Also, add 'precommit' to the .PHONY list in the Makefile and remove the unused ALLOWED_PATTERN variable from the script. Consider clarifying in CONVENTIONS.md how transitive dependencies are handled so enforcement expectations are clear. Once these issues are addressed, the PR should be good to merge.


Review by gpt


Evaluated against 4b96231b

~~Original review~~ **Superseded** — [see current review](https://gitea.weiker.me/rodin/review-bot/pulls/59#pullrequestreview-2158) for up-to-date findings. <details><summary>Previous findings (commit 4b96231b)</summary> # Gpt Review ## Summary Good step toward a controlled allowlist-based dependency policy and automated enforcement. However, the enforcement script hard-codes the allowlist, which diverges from the documented process and can cause drift; also a couple of minor Makefile/script nits. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MAJOR] | `scripts/check-deps.sh` | 8 | The allowlist is hard-coded in the script (ALLOWED array) while CONVENTIONS.md is presented as the source of truth. The documented process says to open a PR that ONLY updates the table, but the enforcement will still fail later unless this script is updated too. This mismatch will cause policy drift and block subsequent PRs using newly approved dependencies. | | 2 | [MINOR] | `CONVENTIONS.md` | 13 | The dependency request process omits updating the enforcement mechanism. If the allowlist remains hard-coded in scripts/check-deps.sh, instructions should explicitly require updating the script alongside the table, or the script should be changed to derive its allowlist from a single canonical source. | | 3 | [MINOR] | `Makefile` | 1 | The new 'precommit' target isn't listed in .PHONY. It should be added to avoid make treating a file named 'precommit' as up-to-date and skipping the target. | | 4 | [NIT] | `scripts/check-deps.sh` | 15 | ALLOWED_PATTERN is built but never used. Remove this dead code to reduce confusion and keep the script minimal. | | 5 | [MINOR] | `CONVENTIONS.md` | 11 | Policy text says 'Only packages listed below may be imported' but the enforcement checks modules via 'go list -m all' and will also block any transitive modules not on the list. Consider clarifying that approving a dependency may entail approving its transitive modules, or adjust the script to allow transitive deps of approved modules automatically. | ## Recommendation **REQUEST_CHANGES** — The policy change and automation are sensible, but the allowlist must have a single source of truth to avoid drift with the documented process. Please either (a) teach scripts/check-deps.sh to parse the allowlist from CONVENTIONS.md (or a separate machine-readable allowlist file that CONVENTIONS.md references), or (b) update CONVENTIONS.md to explicitly require updating scripts/check-deps.sh in the same PR that updates the table. Also, add 'precommit' to the .PHONY list in the Makefile and remove the unused ALLOWED_PATTERN variable from the script. Consider clarifying in CONVENTIONS.md how transitive dependencies are handled so enforcement expectations are clear. Once these issues are addressed, the PR should be good to merge. --- *Review by gpt* <!-- review-bot:gpt --> --- *Evaluated against 4b96231b* </details> <!-- review-bot:gpt -->
CONVENTIONS.md Outdated
@@ -7,0 +8,4 @@
### Approved Third-Party Packages
| Package | Use Case |
|---------|----------|
First-time contributor

[MINOR] Policy text says 'Only packages listed below may be imported' but the enforcement checks modules via 'go list -m all' and will also block any transitive modules not on the list. Consider clarifying that approving a dependency may entail approving its transitive modules, or adjust the script to allow transitive deps of approved modules automatically.

**[MINOR]** Policy text says 'Only packages listed below may be imported' but the enforcement checks modules via 'go list -m all' and will also block any transitive modules not on the list. Consider clarifying that approving a dependency may entail approving its transitive modules, or adjust the script to allow transitive deps of approved modules automatically.
CONVENTIONS.md Outdated
@@ -7,0 +10,4 @@
| Package | Use Case |
|---------|----------|
| `gopkg.in/yaml.v3` | YAML parsing (persona files, config) |
| `github.com/google/go-cmp` | Test comparisons (`cmp.Diff`) |
First-time contributor

[MINOR] The dependency request process omits updating the enforcement mechanism. If the allowlist remains hard-coded in scripts/check-deps.sh, instructions should explicitly require updating the script alongside the table, or the script should be changed to derive its allowlist from a single canonical source.

**[MINOR]** The dependency request process omits updating the enforcement mechanism. If the allowlist remains hard-coded in scripts/check-deps.sh, instructions should explicitly require updating the script alongside the table, or the script should be changed to derive its allowlist from a single canonical source.
Makefile Outdated
@@ -1,4 +1,4 @@
.PHONY: build test test-integration lint clean coverage
.PHONY: build test test-integration lint clean coverage check-deps
First-time contributor

[MINOR] The new 'precommit' target isn't listed in .PHONY. It should be added to avoid make treating a file named 'precommit' as up-to-date and skipping the target.

**[MINOR]** The new 'precommit' target isn't listed in .PHONY. It should be added to avoid make treating a file named 'precommit' as up-to-date and skipping the target.
@@ -0,0 +5,4 @@
set -euo pipefail
# Approved third-party packages (from CONVENTIONS.md)
ALLOWED=(
First-time contributor

[MAJOR] The allowlist is hard-coded in the script (ALLOWED array) while CONVENTIONS.md is presented as the source of truth. The documented process says to open a PR that ONLY updates the table, but the enforcement will still fail later unless this script is updated too. This mismatch will cause policy drift and block subsequent PRs using newly approved dependencies.

**[MAJOR]** The allowlist is hard-coded in the script (ALLOWED array) while CONVENTIONS.md is presented as the source of truth. The documented process says to open a PR that ONLY updates the table, but the enforcement will still fail later unless this script is updated too. This mismatch will cause policy drift and block subsequent PRs using newly approved dependencies.
@@ -0,0 +12,4 @@
# Build regex pattern from allowed list
ALLOWED_PATTERN=""
for pkg in "${ALLOWED[@]}"; do
First-time contributor

[NIT] ALLOWED_PATTERN is built but never used. Remove this dead code to reduce confusion and keep the script minimal.

**[NIT]** ALLOWED_PATTERN is built but never used. Remove this dead code to reduce confusion and keep the script minimal.
rodin added 1 commit 2026-05-10 20:53:57 +00:00
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
70267b68f4
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
sonnet-review-bot approved these changes 2026-05-10 20:54:44 +00:00
sonnet-review-bot left a comment
First-time contributor

Original review

Supersededsee current review for up-to-date findings.

Previous findings (commit 70267b68)

Sonnet Review

Summary

This PR makes a clean policy change: replacing the 'stdlib only' rule with a strict allowlist approach, backed by a well-implemented enforcement script. CI passes. The changes are consistent and the enforcement mechanism is sound.

Findings

# Severity File Line Finding
1 [MINOR] scripts/check-deps.sh 34 The -oP flag for PCRE-style regex (\K) is a GNU grep extension and is not available on macOS (BSD grep). This will silently fail to parse the allowlist on macOS developer machines (the `
2 [MINOR] scripts/check-deps.sh 44 go list -m -f '{{if not .Indirect}}{{.Path}}{{end}}' all lists module-level direct dependencies, not package-level imports. This means a module in go.mod that isn't actually imported in any Go source file will still be flagged. More precisely, it will miss the case where someone adds a go.mod entry for an unapproved module but the script will catch modules not in go.mod at all (since they wouldn't be listed). This is probably fine for the intended purpose, but the comment 'DIRECT dependencies only' may mislead — it means direct in the go.mod sense, not 'actually used in source'. Consider a brief clarifying comment.
3 [NIT] scripts/check-deps.sh 84 The final line counts direct deps via wc -l on $IMPORTS, but $IMPORTS could contain blank lines depending on the go list output format when some template expansions produce empty strings. The grep -v '^$' earlier helps but the count may still be off by one if there's a trailing newline. Minor cosmetic issue.
4 [NIT] CONVENTIONS.md 14 The table lists github.com/google/go-cmp with scope 'test only', but the enforcement script (check-deps.sh) does not differentiate between production and test-only scope — it checks all direct go.mod dependencies uniformly. If go-cmp ends up in go.mod as a direct dependency (which it will when used in _test.go files), it passes the allowlist check regardless of where it's imported. The 'test only' scope annotation is purely documentation with no mechanical enforcement. This is acceptable but worth noting so future maintainers don't assume it's enforced.

Recommendation

APPROVE — Approve. The policy change is well-reasoned, the allowlist is minimal and appropriate (yaml.v3 for production, go-cmp for tests), and the enforcement mechanism is solid. The most notable issue is the GNU grep dependency (-oP) which will silently fail on macOS — worth a follow-up fix or a note in the README/script. The other findings are minor and don't block merging.


Review by sonnet


Evaluated against 70267b68

~~Original review~~ **Superseded** — [see current review](https://gitea.weiker.me/rodin/review-bot/pulls/59#pullrequestreview-2161) for up-to-date findings. <details><summary>Previous findings (commit 70267b68)</summary> # Sonnet Review ## Summary This PR makes a clean policy change: replacing the 'stdlib only' rule with a strict allowlist approach, backed by a well-implemented enforcement script. CI passes. The changes are consistent and the enforcement mechanism is sound. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MINOR] | `scripts/check-deps.sh` | 34 | The `-oP` flag for PCRE-style regex (`\K`) is a GNU grep extension and is not available on macOS (BSD grep). This will silently fail to parse the allowlist on macOS developer machines (the `|| true` swallows the error), leaving ALLOWED empty and triggering the warning but not enforcing anything. Consider using `sed` instead: `echo "$line" | sed -n "s/^| \`\([^\`]*\)\`.*/\1/p"`, or document that GNU grep is required. | | 2 | [MINOR] | `scripts/check-deps.sh` | 44 | `go list -m -f '{{if not .Indirect}}{{.Path}}{{end}}' all` lists module-level direct dependencies, not package-level imports. This means a module in go.mod that isn't actually imported in any Go source file will still be flagged. More precisely, it will miss the case where someone adds a `go.mod` entry for an unapproved module but the script will catch modules not in go.mod at all (since they wouldn't be listed). This is probably fine for the intended purpose, but the comment 'DIRECT dependencies only' may mislead — it means direct in the go.mod sense, not 'actually used in source'. Consider a brief clarifying comment. | | 3 | [NIT] | `scripts/check-deps.sh` | 84 | The final line counts direct deps via `wc -l` on `$IMPORTS`, but `$IMPORTS` could contain blank lines depending on the `go list` output format when some template expansions produce empty strings. The `grep -v '^$'` earlier helps but the count may still be off by one if there's a trailing newline. Minor cosmetic issue. | | 4 | [NIT] | `CONVENTIONS.md` | 14 | The table lists `github.com/google/go-cmp` with scope 'test only', but the enforcement script (`check-deps.sh`) does not differentiate between production and test-only scope — it checks all direct go.mod dependencies uniformly. If `go-cmp` ends up in go.mod as a direct dependency (which it will when used in `_test.go` files), it passes the allowlist check regardless of where it's imported. The 'test only' scope annotation is purely documentation with no mechanical enforcement. This is acceptable but worth noting so future maintainers don't assume it's enforced. | ## Recommendation **APPROVE** — Approve. The policy change is well-reasoned, the allowlist is minimal and appropriate (yaml.v3 for production, go-cmp for tests), and the enforcement mechanism is solid. The most notable issue is the GNU grep dependency (`-oP`) which will silently fail on macOS — worth a follow-up fix or a note in the README/script. The other findings are minor and don't block merging. --- *Review by sonnet* <!-- review-bot:sonnet --> --- *Evaluated against 70267b68* </details> <!-- review-bot:sonnet -->
@@ -7,0 +11,4 @@
|---------|----------|-------|
| `gopkg.in/yaml.v3` | YAML parsing (persona files, config) | production |
| `github.com/google/go-cmp` | Test comparisons (`cmp.Diff`) | test only |
First-time contributor

[NIT] The table lists github.com/google/go-cmp with scope 'test only', but the enforcement script (check-deps.sh) does not differentiate between production and test-only scope — it checks all direct go.mod dependencies uniformly. If go-cmp ends up in go.mod as a direct dependency (which it will when used in _test.go files), it passes the allowlist check regardless of where it's imported. The 'test only' scope annotation is purely documentation with no mechanical enforcement. This is acceptable but worth noting so future maintainers don't assume it's enforced.

**[NIT]** The table lists `github.com/google/go-cmp` with scope 'test only', but the enforcement script (`check-deps.sh`) does not differentiate between production and test-only scope — it checks all direct go.mod dependencies uniformly. If `go-cmp` ends up in go.mod as a direct dependency (which it will when used in `_test.go` files), it passes the allowlist check regardless of where it's imported. The 'test only' scope annotation is purely documentation with no mechanical enforcement. This is acceptable but worth noting so future maintainers don't assume it's enforced.
@@ -0,0 +31,4 @@
# 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) || {
First-time contributor

[MINOR] The -oP flag for PCRE-style regex (\K) is a GNU grep extension and is not available on macOS (BSD grep). This will silently fail to parse the allowlist on macOS developer machines (the || true swallows the error), leaving ALLOWED empty and triggering the warning but not enforcing anything. Consider using sed instead: echo "$line" | sed -n "s/^| \([^`])`./\1/p"`, or document that GNU grep is required.

**[MINOR]** The `-oP` flag for PCRE-style regex (`\K`) is a GNU grep extension and is not available on macOS (BSD grep). This will silently fail to parse the allowlist on macOS developer machines (the `|| true` swallows the error), leaving ALLOWED empty and triggering the warning but not enforcing anything. Consider using `sed` instead: `echo "$line" | sed -n "s/^| \`\([^\`]*\)\`.*/\1/p"`, or document that GNU grep is required.
@@ -0,0 +41,4 @@
if [ -z "$IMPORTS" ]; then
echo "✅ No external dependencies"
exit 0
First-time contributor

[MINOR] go list -m -f '{{if not .Indirect}}{{.Path}}{{end}}' all lists module-level direct dependencies, not package-level imports. This means a module in go.mod that isn't actually imported in any Go source file will still be flagged. More precisely, it will miss the case where someone adds a go.mod entry for an unapproved module but the script will catch modules not in go.mod at all (since they wouldn't be listed). This is probably fine for the intended purpose, but the comment 'DIRECT dependencies only' may mislead — it means direct in the go.mod sense, not 'actually used in source'. Consider a brief clarifying comment.

**[MINOR]** `go list -m -f '{{if not .Indirect}}{{.Path}}{{end}}' all` lists module-level direct dependencies, not package-level imports. This means a module in go.mod that isn't actually imported in any Go source file will still be flagged. More precisely, it will miss the case where someone adds a `go.mod` entry for an unapproved module but the script will catch modules not in go.mod at all (since they wouldn't be listed). This is probably fine for the intended purpose, but the comment 'DIRECT dependencies only' may mislead — it means direct in the go.mod sense, not 'actually used in source'. Consider a brief clarifying comment.
@@ -0,0 +81,4 @@
fi
echo "✅ All dependencies are approved"
echo " Direct deps: $(echo "$IMPORTS" | wc -l | tr -d ' ')"
First-time contributor

[NIT] The final line counts direct deps via wc -l on $IMPORTS, but $IMPORTS could contain blank lines depending on the go list output format when some template expansions produce empty strings. The grep -v '^$' earlier helps but the count may still be off by one if there's a trailing newline. Minor cosmetic issue.

**[NIT]** The final line counts direct deps via `wc -l` on `$IMPORTS`, but `$IMPORTS` could contain blank lines depending on the `go list` output format when some template expansions produce empty strings. The `grep -v '^$'` earlier helps but the count may still be off by one if there's a trailing newline. Minor cosmetic issue.
gpt-review-bot requested changes 2026-05-10 20:55:39 +00:00
gpt-review-bot left a comment
First-time contributor

Original review

Supersededsee current review for up-to-date findings.

Previous findings (commit 70267b68)

Gpt Review

Summary

Good documentation update and a useful enforcement script with Makefile integration. However, the dependency checker does not enforce the documented "Scope" column (e.g., test-only), and relies on GNU grep -P which breaks on macOS, making the enforcement brittle.

Findings

# Severity File Line Finding
1 [MAJOR] scripts/check-deps.sh 20 The script does not enforce the 'Scope' column from CONVENTIONS.md (e.g., allowing github.com/google/go-cmp only in tests). As written, any listed package is allowed in production code, contradicting the documented policy.
2 [MINOR] scripts/check-deps.sh 23 Uses 'grep -P' (Perl regex), which is not available on macOS/BSD grep by default. This reduces cross-platform developer usability for the precommit hook.
3 [MINOR] scripts/check-deps.sh 26 Table parsing relies on a brittle grep pattern ('^| `[a-zA-Z]') and a single-code-cell extraction. Future formatting changes (leading spaces, additional code spans) or package names starting with non-letters may cause false negatives/positives.

Recommendation

REQUEST_CHANGES — Overall the direction is good: documenting an explicit allowlist and adding a precommit target to enforce it. To align implementation with the documented policy and improve robustness:

  1. Enforce 'Scope' semantics:
  • Parse both the package and the scope columns from the Approved Third-Party Packages table.
  • For entries marked 'test only', ensure they do not appear in imports of non-test code. One approach:
    • Scan non-test files for disallowed test-only imports (e.g., grep -R --include='.go' --exclude='_test.go' for those paths) and fail if found; or
    • Use 'go list -deps -test=false ./...' to compute dependencies of non-test builds and verify that test-only modules are absent.
  1. Remove dependency on GNU grep -P for portability:
  • Replace 'grep -oP' with a POSIX-compatible pipeline using awk/sed, or use a small awk parser to extract the first code cell from each table row.
  1. Harden table parsing:
  • Restrict parsing to the Approved Third-Party Packages section (between the header and a blank line or next heading) to avoid accidental matches elsewhere.
  • Relax the initial grep to handle optional leading spaces and not rely on the first character being a letter, or parse the table with awk splitting on '|' and extracting the first backtick-wrapped cell.

With these changes, the enforcement will match the documented policy and work reliably across developer environments. Once addressed, the PR looks good to merge.


Review by gpt


Evaluated against 70267b68

~~Original review~~ **Superseded** — [see current review](https://gitea.weiker.me/rodin/review-bot/pulls/59#pullrequestreview-2164) for up-to-date findings. <details><summary>Previous findings (commit 70267b68)</summary> # Gpt Review ## Summary Good documentation update and a useful enforcement script with Makefile integration. However, the dependency checker does not enforce the documented "Scope" column (e.g., test-only), and relies on GNU grep -P which breaks on macOS, making the enforcement brittle. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MAJOR] | `scripts/check-deps.sh` | 20 | The script does not enforce the 'Scope' column from CONVENTIONS.md (e.g., allowing github.com/google/go-cmp only in tests). As written, any listed package is allowed in production code, contradicting the documented policy. | | 2 | [MINOR] | `scripts/check-deps.sh` | 23 | Uses 'grep -P' (Perl regex), which is not available on macOS/BSD grep by default. This reduces cross-platform developer usability for the precommit hook. | | 3 | [MINOR] | `scripts/check-deps.sh` | 26 | Table parsing relies on a brittle grep pattern ('^\| `[a-zA-Z]') and a single-code-cell extraction. Future formatting changes (leading spaces, additional code spans) or package names starting with non-letters may cause false negatives/positives. | ## Recommendation **REQUEST_CHANGES** — Overall the direction is good: documenting an explicit allowlist and adding a precommit target to enforce it. To align implementation with the documented policy and improve robustness: 1) Enforce 'Scope' semantics: - Parse both the package and the scope columns from the Approved Third-Party Packages table. - For entries marked 'test only', ensure they do not appear in imports of non-test code. One approach: - Scan non-test files for disallowed test-only imports (e.g., grep -R --include='*.go' --exclude='*_test.go' for those paths) and fail if found; or - Use 'go list -deps -test=false ./...' to compute dependencies of non-test builds and verify that test-only modules are absent. 2) Remove dependency on GNU grep -P for portability: - Replace 'grep -oP' with a POSIX-compatible pipeline using awk/sed, or use a small awk parser to extract the first code cell from each table row. 3) Harden table parsing: - Restrict parsing to the Approved Third-Party Packages section (between the header and a blank line or next heading) to avoid accidental matches elsewhere. - Relax the initial grep to handle optional leading spaces and not rely on the first character being a letter, or parse the table with awk splitting on '|' and extracting the first backtick-wrapped cell. With these changes, the enforcement will match the documented policy and work reliably across developer environments. Once addressed, the PR looks good to merge. --- *Review by gpt* <!-- review-bot:gpt --> --- *Evaluated against 70267b68* </details> <!-- review-bot:gpt -->
@@ -0,0 +17,4 @@
# Looks for lines like: | `gopkg.in/yaml.v3` | ...
ALLOWED=()
while IFS= read -r line; do
# Extract package from markdown table cell: | `package` |
First-time contributor

[MAJOR] The script does not enforce the 'Scope' column from CONVENTIONS.md (e.g., allowing github.com/google/go-cmp only in tests). As written, any listed package is allowed in production code, contradicting the documented policy.

**[MAJOR]** The script does not enforce the 'Scope' column from CONVENTIONS.md (e.g., allowing github.com/google/go-cmp only in tests). As written, any listed package is allowed in production code, contradicting the documented policy.
@@ -0,0 +20,4 @@
# Extract package from markdown table cell: | `package` |
pkg=$(echo "$line" | grep -oP '\| `\K[^`]+' | head -1 || true)
if [ -n "$pkg" ] && [[ "$pkg" != "Package" ]]; then
ALLOWED+=("$pkg")
First-time contributor

[MINOR] Uses 'grep -P' (Perl regex), which is not available on macOS/BSD grep by default. This reduces cross-platform developer usability for the precommit hook.

**[MINOR]** Uses 'grep -P' (Perl regex), which is not available on macOS/BSD grep by default. This reduces cross-platform developer usability for the precommit hook.
@@ -0,0 +23,4 @@
ALLOWED+=("$pkg")
fi
done < <(grep -E '^\| `[a-zA-Z]' "$CONVENTIONS_FILE" || true)
First-time contributor

[MINOR] Table parsing relies on a brittle grep pattern ('^| `[a-zA-Z]') and a single-code-cell extraction. Future formatting changes (leading spaces, additional code spans) or package names starting with non-letters may cause false negatives/positives.

**[MINOR]** Table parsing relies on a brittle grep pattern ('^\| `[a-zA-Z]') and a single-code-cell extraction. Future formatting changes (leading spaces, additional code spans) or package names starting with non-letters may cause false negatives/positives.
security-review-bot requested review from security-review-bot 2026-05-10 20:55:40 +00:00
security-review-bot approved these changes 2026-05-10 20:55:40 +00:00
Dismissed
security-review-bot left a comment
Collaborator

Security Review

Summary

The PR introduces a strict, documented dependency allowlist and enforces it via a precommit script. CI passed and no exploitable vulnerabilities are introduced; the enforcement script is generally sound.

Findings

# Severity File Line Finding
1 [MINOR] scripts/check-deps.sh 54 The prefix match uses , which treats the right side as a glob pattern. While allowed entries are controlled via review, a metacharacter (e.g., *, ?, [) in an approved package could unintentionally broaden matches. Consider a literal prefix check to avoid glob semantics.

Recommendation

APPROVE — Approve the changes. The dependency allowlist policy and enforcement improve supply chain hygiene without introducing security risks. As a defense-in-depth hardening, modify the dependency match to use a literal prefix comparison rather than glob patterns (e.g., use parameter expansion: if || ; then MATCHED=true; fi). This prevents any accidental glob characters in the allowlist from broadening matches. Otherwise, the implementation is sound and aligns with the documented process.


Review by security


Evaluated against 70267b68

# Security Review ## Summary The PR introduces a strict, documented dependency allowlist and enforces it via a precommit script. CI passed and no exploitable vulnerabilities are introduced; the enforcement script is generally sound. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MINOR] | `scripts/check-deps.sh` | 54 | The prefix match uses [[ "$import" == "$allowed/"* ]], which treats the right side as a glob pattern. While allowed entries are controlled via review, a metacharacter (e.g., *, ?, [) in an approved package could unintentionally broaden matches. Consider a literal prefix check to avoid glob semantics. | ## Recommendation **APPROVE** — Approve the changes. The dependency allowlist policy and enforcement improve supply chain hygiene without introducing security risks. As a defense-in-depth hardening, modify the dependency match to use a literal prefix comparison rather than glob patterns (e.g., use parameter expansion: if [[ "$import" == "$allowed" ]] || [[ "${import#${allowed}/}" != "$import" ]]; then MATCHED=true; fi). This prevents any accidental glob characters in the allowlist from broadening matches. Otherwise, the implementation is sound and aligns with the documented process. --- *Review by security* <!-- review-bot:security --> --- *Evaluated against 70267b68*
@@ -0,0 +51,4 @@
# Check if import matches any allowed package (prefix match for subpackages)
MATCHED=false
for allowed in "${ALLOWED[@]}"; do
if [[ "$import" == "$allowed" ]] || [[ "$import" == "$allowed/"* ]]; then
Collaborator

[MINOR] The prefix match uses , which treats the right side as a glob pattern. While allowed entries are controlled via review, a metacharacter (e.g., *, ?, [) in an approved package could unintentionally broaden matches. Consider a literal prefix check to avoid glob semantics.

**[MINOR]** The prefix match uses [[ "$import" == "$allowed/"* ]], which treats the right side as a glob pattern. While allowed entries are controlled via review, a metacharacter (e.g., *, ?, [) in an approved package could unintentionally broaden matches. Consider a literal prefix check to avoid glob semantics.
rodin added 1 commit 2026-05-10 20:57:50 +00:00
fix: enforce Scope column and improve portability
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 35s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m46s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 2m2s
aeb0c8cb79
Addresses review feedback:

1. MAJOR - Scope enforcement: Script now parses the Scope column and
   ensures 'test only' packages don't appear in non-test code. Uses
   'go list -deps' to check production imports.

2. MINOR - Portability: Replaced 'grep -P' (GNU-only) with awk-based
   parsing that works on macOS/BSD.

3. MINOR - Robustness: Table parsing uses awk to split on '|' and
   extract columns properly, handling whitespace variations.

4. MINOR - Glob safety: Prefix matching now uses parameter expansion
   instead of glob patterns to prevent metacharacter issues.
sonnet-review-bot approved these changes 2026-05-10 20:58:41 +00:00
sonnet-review-bot left a comment
First-time contributor

Original review

Supersededsee current review for up-to-date findings.

Previous findings (commit aeb0c8cb)

Sonnet Review

Summary

This PR replaces the 'stdlib only' policy with a well-structured strict allowlist enforced by a new check-deps.sh script and Makefile target. The changes are coherent, CI passes, and the enforcement tooling is solid. A few minor issues in the shell script deserve attention but none are blockers.

Findings

# Severity File Line Finding
1 [MINOR] scripts/check-deps.sh 68 The go list -m output includes the current module itself on the first line, and the comment says 'Filter out the module itself (first line)'. However, tail -n +2 strips the first line unconditionally. If go list -m ... all ever reorders output or includes a blank first line (e.g., when run in a workspace), this assumption breaks silently. A more robust approach would be to filter by comparing against $(go list -m) (the current module path) rather than relying on line position.
2 [MINOR] scripts/check-deps.sh 99 The test-scope enforcement uses `go list -deps -f '...' ./...
3 [MINOR] scripts/check-deps.sh 108 The test-only production check uses grep -q "^${test_pkg}" without anchoring the end of the pattern. A package path like github.com/google/go-cmp would inadvertently match a hypothetical github.com/google/go-cmp-extended. Should be `grep -qE "^${test_pkg}(/
4 [NIT] scripts/check-deps.sh 22 The comment says 'POSIX-compatible' but declare -A (associative arrays) is a bash 4+ feature and is not POSIX. The comment should say 'bash 4+' to accurately describe the requirement. macOS ships bash 3.2 by default (GPLv2 licensing constraint), so this script would fail on stock macOS without Homebrew bash. Worth documenting the bash version requirement in a shebang comment or README.
5 [NIT] CONVENTIONS.md 20 The sentence 'Transitive dependencies of approved packages are automatically allowed' is a policy statement that the check-deps.sh script does NOT currently verify (it only checks direct deps via go list -m). This is correct behavior—you generally don't want to enumerate all transitive deps—but the wording could be clearer: something like 'Transitive dependencies pulled in by approved packages do not need to be listed here' to make it clear this is intentional, not an oversight.

Recommendation

APPROVE — Approve. CI passes and the change is coherent and well-designed. The policy documentation is clear, the single-source-of-truth approach (parsing CONVENTIONS.md) is smart, and the Makefile integration via precommit target is exactly right. The MINOR findings (grep anchoring bug, bash version caveat) are worth a follow-up but don't block merging—the grep issue in particular could produce a false negative in an unlikely edge case but would not produce a false positive (it wouldn't miss real violations). The NIT about transitive dep wording is purely cosmetic.


Review by sonnet


Evaluated against aeb0c8cb

~~Original review~~ **Superseded** — [see current review](https://gitea.weiker.me/rodin/review-bot/pulls/59#pullrequestreview-2165) for up-to-date findings. <details><summary>Previous findings (commit aeb0c8cb)</summary> # Sonnet Review ## Summary This PR replaces the 'stdlib only' policy with a well-structured strict allowlist enforced by a new check-deps.sh script and Makefile target. The changes are coherent, CI passes, and the enforcement tooling is solid. A few minor issues in the shell script deserve attention but none are blockers. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MINOR] | `scripts/check-deps.sh` | 68 | The `go list -m` output includes the current module itself on the first line, and the comment says 'Filter out the module itself (first line)'. However, `tail -n +2` strips the first line unconditionally. If `go list -m ... all` ever reorders output or includes a blank first line (e.g., when run in a workspace), this assumption breaks silently. A more robust approach would be to filter by comparing against `$(go list -m)` (the current module path) rather than relying on line position. | | 2 | [MINOR] | `scripts/check-deps.sh` | 99 | The test-scope enforcement uses `go list -deps -f '...' ./... | grep -v '_test'` to identify production imports, but this approach is fragile: it filters by path containing '_test', which catches test packages but the `-deps` flag on non-test packages already excludes test files. More importantly, this will fail to detect a test-only package imported via a non-test file in a sub-package whose path happens not to contain '_test'. Using `go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' $(go list ./...)` (without `-deps`) and then checking against the allowlist directly would be more precise. That said, the current approach is a reasonable heuristic. | | 3 | [MINOR] | `scripts/check-deps.sh` | 108 | The test-only production check uses `grep -q "^${test_pkg}"` without anchoring the end of the pattern. A package path like `github.com/google/go-cmp` would inadvertently match a hypothetical `github.com/google/go-cmp-extended`. Should be `grep -qE "^${test_pkg}(/|$)"` to match only exact or subpackage imports. | | 4 | [NIT] | `scripts/check-deps.sh` | 22 | The comment says 'POSIX-compatible' but `declare -A` (associative arrays) is a bash 4+ feature and is not POSIX. The comment should say 'bash 4+' to accurately describe the requirement. macOS ships bash 3.2 by default (GPLv2 licensing constraint), so this script would fail on stock macOS without Homebrew bash. Worth documenting the bash version requirement in a shebang comment or README. | | 5 | [NIT] | `CONVENTIONS.md` | 20 | The sentence 'Transitive dependencies of approved packages are automatically allowed' is a policy statement that the check-deps.sh script does NOT currently verify (it only checks direct deps via `go list -m`). This is correct behavior—you generally don't want to enumerate all transitive deps—but the wording could be clearer: something like 'Transitive dependencies pulled in by approved packages do not need to be listed here' to make it clear this is intentional, not an oversight. | ## Recommendation **APPROVE** — Approve. CI passes and the change is coherent and well-designed. The policy documentation is clear, the single-source-of-truth approach (parsing CONVENTIONS.md) is smart, and the Makefile integration via `precommit` target is exactly right. The MINOR findings (grep anchoring bug, bash version caveat) are worth a follow-up but don't block merging—the grep issue in particular could produce a false negative in an unlikely edge case but would not produce a false positive (it wouldn't miss real violations). The NIT about transitive dep wording is purely cosmetic. --- *Review by sonnet* <!-- review-bot:sonnet --> --- *Evaluated against aeb0c8cb* </details> <!-- review-bot:sonnet -->
@@ -7,0 +17,4 @@
Transitive dependencies of approved packages are automatically allowed.
To request a new dependency:
1. Open a PR that ONLY updates this table
First-time contributor

[NIT] The sentence 'Transitive dependencies of approved packages are automatically allowed' is a policy statement that the check-deps.sh script does NOT currently verify (it only checks direct deps via go list -m). This is correct behavior—you generally don't want to enumerate all transitive deps—but the wording could be clearer: something like 'Transitive dependencies pulled in by approved packages do not need to be listed here' to make it clear this is intentional, not an oversight.

**[NIT]** The sentence 'Transitive dependencies of approved packages are automatically allowed' is a policy statement that the check-deps.sh script does NOT currently verify (it only checks direct deps via `go list -m`). This is correct behavior—you generally don't want to enumerate all transitive deps—but the wording could be clearer: something like 'Transitive dependencies pulled in by approved packages do not need to be listed here' to make it clear this is intentional, not an oversight.
@@ -0,0 +19,4 @@
# Output: package:scope (e.g., "gopkg.in/yaml.v3:production")
declare -A ALLOWED_PROD=()
declare -A ALLOWED_TEST=()
First-time contributor

[NIT] The comment says 'POSIX-compatible' but declare -A (associative arrays) is a bash 4+ feature and is not POSIX. The comment should say 'bash 4+' to accurately describe the requirement. macOS ships bash 3.2 by default (GPLv2 licensing constraint), so this script would fail on stock macOS without Homebrew bash. Worth documenting the bash version requirement in a shebang comment or README.

**[NIT]** The comment says 'POSIX-compatible' but `declare -A` (associative arrays) is a bash 4+ feature and is not POSIX. The comment should say 'bash 4+' to accurately describe the requirement. macOS ships bash 3.2 by default (GPLv2 licensing constraint), so this script would fail on stock macOS without Homebrew bash. Worth documenting the bash version requirement in a shebang comment or README.
@@ -0,0 +65,4 @@
# 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
First-time contributor

[MINOR] The go list -m output includes the current module itself on the first line, and the comment says 'Filter out the module itself (first line)'. However, tail -n +2 strips the first line unconditionally. If go list -m ... all ever reorders output or includes a blank first line (e.g., when run in a workspace), this assumption breaks silently. A more robust approach would be to filter by comparing against $(go list -m) (the current module path) rather than relying on line position.

**[MINOR]** The `go list -m` output includes the current module itself on the first line, and the comment says 'Filter out the module itself (first line)'. However, `tail -n +2` strips the first line unconditionally. If `go list -m ... all` ever reorders output or includes a blank first line (e.g., when run in a workspace), this assumption breaks silently. A more robust approach would be to filter by comparing against `$(go list -m)` (the current module path) rather than relying on line position.
@@ -0,0 +96,4 @@
exit 1
fi
# Enforce Scope: test-only packages must not appear in non-test code
First-time contributor

[MINOR] The test-scope enforcement uses go list -deps -f '...' ./... | grep -v '_test' to identify production imports, but this approach is fragile: it filters by path containing '_test', which catches test packages but the -deps flag on non-test packages already excludes test files. More importantly, this will fail to detect a test-only package imported via a non-test file in a sub-package whose path happens not to contain '_test'. Using go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' $(go list ./...) (without -deps) and then checking against the allowlist directly would be more precise. That said, the current approach is a reasonable heuristic.

**[MINOR]** The test-scope enforcement uses `go list -deps -f '...' ./... | grep -v '_test'` to identify production imports, but this approach is fragile: it filters by path containing '_test', which catches test packages but the `-deps` flag on non-test packages already excludes test files. More importantly, this will fail to detect a test-only package imported via a non-test file in a sub-package whose path happens not to contain '_test'. Using `go list -f '{{if not .Standard}}{{.ImportPath}}{{end}}' $(go list ./...)` (without `-deps`) and then checking against the allowlist directly would be more precise. That said, the current approach is a reasonable heuristic.
@@ -0,0 +105,4 @@
if echo "$PROD_IMPORTS" | grep -q "^${test_pkg}"; then
TEST_ONLY_IN_PROD="${TEST_ONLY_IN_PROD} - ${test_pkg} (marked 'test only' but used in production code)"$'\n'
fi
done
First-time contributor

[MINOR] The test-only production check uses grep -q "^${test_pkg}" without anchoring the end of the pattern. A package path like github.com/google/go-cmp would inadvertently match a hypothetical github.com/google/go-cmp-extended. Should be grep -qE "^${test_pkg}(/|$)" to match only exact or subpackage imports.

**[MINOR]** The test-only production check uses `grep -q "^${test_pkg}"` without anchoring the end of the pattern. A package path like `github.com/google/go-cmp` would inadvertently match a hypothetical `github.com/google/go-cmp-extended`. Should be `grep -qE "^${test_pkg}(/|$)"` to match only exact or subpackage imports.
security-review-bot requested review from security-review-bot 2026-05-10 20:59:53 +00:00
security-review-bot approved these changes 2026-05-10 20:59:54 +00:00
Dismissed
security-review-bot left a comment
Collaborator

Security Review

Summary

Changes add a strict allowlist for third-party dependencies with an enforcement script and integrate it into the build. CI passed and the enforcement logic is generally sound with no exploitable vulnerabilities found.

Findings

# Severity File Line Finding
1 [MINOR] scripts/check-deps.sh 105 The grep check for test-only packages in production uses an unescaped regex pattern (grep -q "^${test_pkg}"). If a package name contains regex metacharacters (e.g., dots), this may match unintended imports. While not a code execution risk, it can cause false positives/negatives in enforcement.
2 [MINOR] scripts/check-deps.sh 101 Production imports discovery allows go list to fail open (2>/dev/null

Recommendation

APPROVE — Overall, the dependency policy update and enforcement mechanism look solid and CI passed. Approve the PR. As hardening improvements, consider: (1) escaping package names when grepping for test-only packages in production (e.g., use grep -F or escape metacharacters and match ^(/|$) to avoid regex-induced mismatches); and (2) avoid swallowing errors when listing production imports—if go list -deps fails, exit non-zero rather than proceeding, to fail closed. These changes will make enforcement more reliable without altering intended behavior.


Review by security


Evaluated against aeb0c8cb

# Security Review ## Summary Changes add a strict allowlist for third-party dependencies with an enforcement script and integrate it into the build. CI passed and the enforcement logic is generally sound with no exploitable vulnerabilities found. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MINOR] | `scripts/check-deps.sh` | 105 | The grep check for test-only packages in production uses an unescaped regex pattern (grep -q "^${test_pkg}"). If a package name contains regex metacharacters (e.g., dots), this may match unintended imports. While not a code execution risk, it can cause false positives/negatives in enforcement. | | 2 | [MINOR] | `scripts/check-deps.sh` | 101 | Production imports discovery allows go list to fail open (2>/dev/null | ... || true). If go list fails, PROD_IMPORTS becomes empty and the script won’t detect misuse of test-only dependencies, weakening enforcement. Failing closed here would improve robustness. | ## Recommendation **APPROVE** — Overall, the dependency policy update and enforcement mechanism look solid and CI passed. Approve the PR. As hardening improvements, consider: (1) escaping package names when grepping for test-only packages in production (e.g., use grep -F or escape metacharacters and match ^<pkg>(/|$) to avoid regex-induced mismatches); and (2) avoid swallowing errors when listing production imports—if go list -deps fails, exit non-zero rather than proceeding, to fail closed. These changes will make enforcement more reliable without altering intended behavior. --- *Review by security* <!-- review-bot:security --> --- *Evaluated against aeb0c8cb*
@@ -0,0 +98,4 @@
# Enforce Scope: test-only packages must not appear in non-test code
# Get imports used by non-test code only
PROD_IMPORTS=$(go list -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./... 2>/dev/null | grep -v '_test' || true)
Collaborator

[MINOR] Production imports discovery allows go list to fail open (2>/dev/null | ... || true). If go list fails, PROD_IMPORTS becomes empty and the script won’t detect misuse of test-only dependencies, weakening enforcement. Failing closed here would improve robustness.

**[MINOR]** Production imports discovery allows go list to fail open (2>/dev/null | ... || true). If go list fails, PROD_IMPORTS becomes empty and the script won’t detect misuse of test-only dependencies, weakening enforcement. Failing closed here would improve robustness.
@@ -0,0 +102,4 @@
TEST_ONLY_IN_PROD=""
for test_pkg in "${!ALLOWED_TEST[@]}"; do
if echo "$PROD_IMPORTS" | grep -q "^${test_pkg}"; then
Collaborator

[MINOR] The grep check for test-only packages in production uses an unescaped regex pattern (grep -q "^${test_pkg}"). If a package name contains regex metacharacters (e.g., dots), this may match unintended imports. While not a code execution risk, it can cause false positives/negatives in enforcement.

**[MINOR]** The grep check for test-only packages in production uses an unescaped regex pattern (grep -q "^${test_pkg}"). If a package name contains regex metacharacters (e.g., dots), this may match unintended imports. While not a code execution risk, it can cause false positives/negatives in enforcement.
gpt-review-bot requested changes 2026-05-10 21:00:07 +00:00
gpt-review-bot left a comment
First-time contributor

Original review

Supersededsee current review for up-to-date findings.

Previous findings (commit aeb0c8cb)

Gpt Review

Summary

The policy update and Makefile integration look good, but the dependency enforcement script has a critical gap: it does not validate test-only dependencies against the allowlist, allowing unapproved test deps to slip through. There are also a couple of robustness issues in prefix matching and portability.

Findings

# Severity File Line Finding
1 [MAJOR] scripts/check-deps.sh 65 The script checks only direct non-test modules via go list -m ... all and never verifies test-only dependencies against the allowlist. As a result, importing any new third-party package in tests (e.g., in *_test.go) will not be flagged unless also used in production code. This violates the documented 'STRICT ALLOWLIST' policy for tests.
2 [MINOR] scripts/check-deps.sh 103 The scope enforcement uses grep -q "^${test_pkg}" which can produce false positives for modules with a similar prefix (e.g., github.com/google/go-cmppro would match github.com/google/go-cmp). Use a delimiter-aware pattern like `^${test_pkg}(/
3 [MINOR] scripts/check-deps.sh 20 The script relies on bash associative arrays (declare -A), which require Bash 4+. On macOS (default Bash 3.2), this will fail locally for contributors running make precommit. Consider documenting the requirement, invoking a known shell (e.g., via env bash with ensured version), or rewriting to avoid associative arrays.
4 [NIT] scripts/check-deps.sh 99 The grep -v '_test' in the production imports step is unnecessary because go list -deps without -test already excludes test-only dependencies. While harmless, it can be removed for clarity.

Recommendation

REQUEST_CHANGES — Overall the policy change and Makefile additions are sensible, but please fix the enforcement gap before merging. Specifically: (1) Extend the script to validate test dependencies against the allowlist. For example, run go list -test -m -f '{{if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all (or a suitable go list -deps -test variant that maps packages to modules) and ensure each test module matches either the production or test-only allowlist. This will prevent unapproved test-only packages from being introduced. (2) Tighten the regex used to detect test-only packages in production code to ^${test_pkg}(/|$) to avoid false positives on similarly prefixed modules. (3) Address portability by documenting a Bash 4+ requirement for precommit or refactoring to avoid associative arrays so local contributors on macOS aren't blocked. (4) Optionally remove the redundant _test filter in the production imports step for clarity. After these changes, the script will correctly enforce the strict allowlist for both production and test dependencies as documented, and the PR can be approved.


Review by gpt


Evaluated against aeb0c8cb

~~Original review~~ **Superseded** — [see current review](https://gitea.weiker.me/rodin/review-bot/pulls/59#pullrequestreview-2166) for up-to-date findings. <details><summary>Previous findings (commit aeb0c8cb)</summary> # Gpt Review ## Summary The policy update and Makefile integration look good, but the dependency enforcement script has a critical gap: it does not validate test-only dependencies against the allowlist, allowing unapproved test deps to slip through. There are also a couple of robustness issues in prefix matching and portability. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MAJOR] | `scripts/check-deps.sh` | 65 | The script checks only direct non-test modules via `go list -m ... all` and never verifies test-only dependencies against the allowlist. As a result, importing any new third-party package in tests (e.g., in *_test.go) will not be flagged unless also used in production code. This violates the documented 'STRICT ALLOWLIST' policy for tests. | | 2 | [MINOR] | `scripts/check-deps.sh` | 103 | The scope enforcement uses `grep -q "^${test_pkg}"` which can produce false positives for modules with a similar prefix (e.g., github.com/google/go-cmppro would match github.com/google/go-cmp). Use a delimiter-aware pattern like `^${test_pkg}(/|$)` to avoid accidental matches. | | 3 | [MINOR] | `scripts/check-deps.sh` | 20 | The script relies on bash associative arrays (`declare -A`), which require Bash 4+. On macOS (default Bash 3.2), this will fail locally for contributors running `make precommit`. Consider documenting the requirement, invoking a known shell (e.g., via `env bash` with ensured version), or rewriting to avoid associative arrays. | | 4 | [NIT] | `scripts/check-deps.sh` | 99 | The `grep -v '_test'` in the production imports step is unnecessary because `go list -deps` without `-test` already excludes test-only dependencies. While harmless, it can be removed for clarity. | ## Recommendation **REQUEST_CHANGES** — Overall the policy change and Makefile additions are sensible, but please fix the enforcement gap before merging. Specifically: (1) Extend the script to validate test dependencies against the allowlist. For example, run `go list -test -m -f '{{if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all` (or a suitable `go list -deps -test` variant that maps packages to modules) and ensure each test module matches either the production or test-only allowlist. This will prevent unapproved test-only packages from being introduced. (2) Tighten the regex used to detect test-only packages in production code to `^${test_pkg}(/|$)` to avoid false positives on similarly prefixed modules. (3) Address portability by documenting a Bash 4+ requirement for `precommit` or refactoring to avoid associative arrays so local contributors on macOS aren't blocked. (4) Optionally remove the redundant `_test` filter in the production imports step for clarity. After these changes, the script will correctly enforce the strict allowlist for both production and test dependencies as documented, and the PR can be approved. --- *Review by gpt* <!-- review-bot:gpt --> --- *Evaluated against aeb0c8cb* </details> <!-- review-bot:gpt -->
@@ -0,0 +17,4 @@
# Parse approved packages from CONVENTIONS.md table using awk (POSIX-compatible)
# Format: | `package` | use case | scope |
# Output: package:scope (e.g., "gopkg.in/yaml.v3:production")
declare -A ALLOWED_PROD=()
First-time contributor

[MINOR] The script relies on bash associative arrays (declare -A), which require Bash 4+. On macOS (default Bash 3.2), this will fail locally for contributors running make precommit. Consider documenting the requirement, invoking a known shell (e.g., via env bash with ensured version), or rewriting to avoid associative arrays.

**[MINOR]** The script relies on bash associative arrays (`declare -A`), which require Bash 4+. On macOS (default Bash 3.2), this will fail locally for contributors running `make precommit`. Consider documenting the requirement, invoking a known shell (e.g., via `env bash` with ensured version), or rewriting to avoid associative arrays.
@@ -0,0 +62,4 @@
}
# Get DIRECT dependencies only (exclude indirect/transitive)
# Fail closed: if go list fails, we exit non-zero
First-time contributor

[MAJOR] The script checks only direct non-test modules via go list -m ... all and never verifies test-only dependencies against the allowlist. As a result, importing any new third-party package in tests (e.g., in *_test.go) will not be flagged unless also used in production code. This violates the documented 'STRICT ALLOWLIST' policy for tests.

**[MAJOR]** The script checks only direct non-test modules via `go list -m ... all` and never verifies test-only dependencies against the allowlist. As a result, importing any new third-party package in tests (e.g., in *_test.go) will not be flagged unless also used in production code. This violates the documented 'STRICT ALLOWLIST' policy for tests.
@@ -0,0 +96,4 @@
exit 1
fi
# Enforce Scope: test-only packages must not appear in non-test code
First-time contributor

[NIT] The grep -v '_test' in the production imports step is unnecessary because go list -deps without -test already excludes test-only dependencies. While harmless, it can be removed for clarity.

**[NIT]** The `grep -v '_test'` in the production imports step is unnecessary because `go list -deps` without `-test` already excludes test-only dependencies. While harmless, it can be removed for clarity.
@@ -0,0 +100,4 @@
# Get imports used by non-test code only
PROD_IMPORTS=$(go list -deps -f '{{if not .Standard}}{{.ImportPath}}{{end}}' ./... 2>/dev/null | grep -v '_test' || true)
TEST_ONLY_IN_PROD=""
First-time contributor

[MINOR] The scope enforcement uses grep -q "^${test_pkg}" which can produce false positives for modules with a similar prefix (e.g., github.com/google/go-cmppro would match github.com/google/go-cmp). Use a delimiter-aware pattern like ^${test_pkg}(/|$) to avoid accidental matches.

**[MINOR]** The scope enforcement uses `grep -q "^${test_pkg}"` which can produce false positives for modules with a similar prefix (e.g., github.com/google/go-cmppro would match github.com/google/go-cmp). Use a delimiter-aware pattern like `^${test_pkg}(/|$)` to avoid accidental matches.
rodin added 1 commit 2026-05-10 21:02:07 +00:00
fix: validate all deps and improve robustness
PR Ready Gate / clear-labels (pull_request) Successful in 1s
CI / test (pull_request) Successful in 15s
CI / review (anthropic--claude-4.6-sonnet, sonnet, SONNET_REVIEW_TOKEN) (pull_request) Successful in 34s
CI / review (gpt-5, gpt, GPT_REVIEW_TOKEN) (pull_request) Successful in 1m51s
CI / review (gpt-5, security, SECURITY_REVIEW.md, SECURITY_REVIEW_TOKEN) (pull_request) Successful in 1m51s
01cde16d47
Addresses GPT review feedback:

1. MAJOR - Test deps now validated: All direct module deps (from go.mod)
   are checked against the allowlist, whether used in prod or tests.

2. MINOR - Prefix match: Uses grep -E with word boundary (^pkg(/|$|$))
   to avoid false positives on similarly-prefixed modules.

3. MINOR - Bash version check: Script now fails early with helpful
   message if Bash < 4 (macOS default). Added shebang: #!/usr/bin/env bash

4. NIT - Removed redundant grep -v '_test' (go list -deps already
   excludes test-only deps without -test flag).
sonnet-review-bot approved these changes 2026-05-10 21:02:56 +00:00
sonnet-review-bot left a comment
First-time contributor

Sonnet Review

Summary

This PR replaces the blunt 'stdlib only' rule with a well-structured allowlist system, complete with enforcement tooling. The CONVENTIONS.md change is clear and the check-deps.sh script is solid overall. CI passes. A few minor issues in the script are worth noting but don't block merge.

Findings

# Severity File Line Finding
1 [MINOR] scripts/check-deps.sh 73 The script checks go.mod direct dependencies for allowlist compliance, but the scope enforcement (lines 97-111) checks the full production import graph via go list -deps. These two checks are at different granularities and could diverge. For example, a direct dependency might be test-only in practice but go list -deps ./... (which doesn't filter test files) would still traverse it. Using go list -deps -test=false ./... more explicitly conveys intent, though the current flag-less form already excludes test builds.
2 [MINOR] scripts/check-deps.sh 104 The regex `"^${test_pkg}(/
3 [MINOR] scripts/check-deps.sh 71 If go list returns non-module output (e.g. build errors) the error is captured in DIRECT_IMPORTS and the early-exit error message will contain the raw go toolchain output. This works adequately but the error message could be confusing. Minor quality-of-life issue.
4 [NIT] scripts/check-deps.sh 57 The comment says 'POSIX-compatible' for the awk parsing but the outer loop uses a Bash process substitution < <(...) which is Bash-specific. The comment is mildly misleading — it means awk itself is POSIX, not the overall approach.
5 [NIT] CONVENTIONS.md 14 The note 'Transitive dependencies of approved packages are automatically allowed' is a policy statement, but the enforcement script only checks direct module dependencies (via go list -m ... all with .Indirect filtered out). This is correct and intentional, but it's worth confirming the wording matches: transitive deps won't appear as violations, which aligns with the statement.

Recommendation

APPROVE — Approve. The change is well-reasoned, well-documented, and the enforcement script is functional and correct for its intended purpose. CI passes. The minor issues noted (regex redundancy, comment accuracy) are cosmetic and do not affect correctness. The policy itself — strict allowlist with a clear process for additions — is a significant improvement over either 'stdlib only' or uncontrolled dependency growth.


Review by sonnet


Evaluated against 01cde16d

# Sonnet Review ## Summary This PR replaces the blunt 'stdlib only' rule with a well-structured allowlist system, complete with enforcement tooling. The CONVENTIONS.md change is clear and the check-deps.sh script is solid overall. CI passes. A few minor issues in the script are worth noting but don't block merge. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MINOR] | `scripts/check-deps.sh` | 73 | The script checks `go.mod` direct dependencies for allowlist compliance, but the scope enforcement (lines 97-111) checks the full production import graph via `go list -deps`. These two checks are at different granularities and could diverge. For example, a direct dependency might be test-only in practice but `go list -deps ./...` (which doesn't filter test files) would still traverse it. Using `go list -deps -test=false ./...` more explicitly conveys intent, though the current flag-less form already excludes test builds. | | 2 | [MINOR] | `scripts/check-deps.sh` | 104 | The regex `"^${test_pkg}(/|\$|$)"` has a redundant `$` — `\$` escapes the literal dollar sign for the shell but in the regex context inside `grep -qE`, the trailing `|$)` is a proper end-of-line anchor followed by the closing group, making `\$` (literal `$` character) unreachable in practice. This is harmless but the intent (match exact package or subpackage) is already handled by the `^pkg($|/)` pattern. Consider simplifying to `"^${test_pkg}(/|$)"`. | | 3 | [MINOR] | `scripts/check-deps.sh` | 71 | If `go list` returns non-module output (e.g. build errors) the error is captured in `DIRECT_IMPORTS` and the early-exit error message will contain the raw go toolchain output. This works adequately but the error message could be confusing. Minor quality-of-life issue. | | 4 | [NIT] | `scripts/check-deps.sh` | 57 | The comment says 'POSIX-compatible' for the awk parsing but the outer loop uses a Bash process substitution `< <(...)` which is Bash-specific. The comment is mildly misleading — it means awk itself is POSIX, not the overall approach. | | 5 | [NIT] | `CONVENTIONS.md` | 14 | The note 'Transitive dependencies of approved packages are automatically allowed' is a policy statement, but the enforcement script only checks direct module dependencies (via `go list -m ... all` with `.Indirect` filtered out). This is correct and intentional, but it's worth confirming the wording matches: transitive deps won't appear as violations, which aligns with the statement. | ## Recommendation **APPROVE** — Approve. The change is well-reasoned, well-documented, and the enforcement script is functional and correct for its intended purpose. CI passes. The minor issues noted (regex redundancy, comment accuracy) are cosmetic and do not affect correctness. The policy itself — strict allowlist with a clear process for additions — is a significant improvement over either 'stdlib only' or uncontrolled dependency growth. --- *Review by sonnet* <!-- review-bot:sonnet --> --- *Evaluated against 01cde16d*
@@ -7,0 +11,4 @@
|---------|----------|-------|
| `gopkg.in/yaml.v3` | YAML parsing (persona files, config) | production |
| `github.com/google/go-cmp` | Test comparisons (`cmp.Diff`) | test only |
First-time contributor

[NIT] The note 'Transitive dependencies of approved packages are automatically allowed' is a policy statement, but the enforcement script only checks direct module dependencies (via go list -m ... all with .Indirect filtered out). This is correct and intentional, but it's worth confirming the wording matches: transitive deps won't appear as violations, which aligns with the statement.

**[NIT]** The note 'Transitive dependencies of approved packages are automatically allowed' is a policy statement, but the enforcement script only checks direct module dependencies (via `go list -m ... all` with `.Indirect` filtered out). This is correct and intentional, but it's worth confirming the wording matches: transitive deps won't appear as violations, which aligns with the statement.
@@ -0,0 +54,4 @@
local import="$1"
shift
local -n allowlist=$1
First-time contributor

[NIT] The comment says 'POSIX-compatible' for the awk parsing but the outer loop uses a Bash process substitution < <(...) which is Bash-specific. The comment is mildly misleading — it means awk itself is POSIX, not the overall approach.

**[NIT]** The comment says 'POSIX-compatible' for the awk parsing but the outer loop uses a Bash process substitution `< <(...)` which is Bash-specific. The comment is mildly misleading — it means awk itself is POSIX, not the overall approach.
@@ -0,0 +68,4 @@
return 1
}
# Get direct module dependencies from go.mod
First-time contributor

[MINOR] If go list returns non-module output (e.g. build errors) the error is captured in DIRECT_IMPORTS and the early-exit error message will contain the raw go toolchain output. This works adequately but the error message could be confusing. Minor quality-of-life issue.

**[MINOR]** If `go list` returns non-module output (e.g. build errors) the error is captured in `DIRECT_IMPORTS` and the early-exit error message will contain the raw go toolchain output. This works adequately but the error message could be confusing. Minor quality-of-life issue.
@@ -0,0 +70,4 @@
# Get direct module dependencies from go.mod
DIRECT_IMPORTS=$(go list -m -f '{{if and (not .Indirect) (not .Main)}}{{.Path}}{{end}}' all 2>&1) || {
echo "❌ Failed to list dependencies: $DIRECT_IMPORTS"
First-time contributor

[MINOR] The script checks go.mod direct dependencies for allowlist compliance, but the scope enforcement (lines 97-111) checks the full production import graph via go list -deps. These two checks are at different granularities and could diverge. For example, a direct dependency might be test-only in practice but go list -deps ./... (which doesn't filter test files) would still traverse it. Using go list -deps -test=false ./... more explicitly conveys intent, though the current flag-less form already excludes test builds.

**[MINOR]** The script checks `go.mod` direct dependencies for allowlist compliance, but the scope enforcement (lines 97-111) checks the full production import graph via `go list -deps`. These two checks are at different granularities and could diverge. For example, a direct dependency might be test-only in practice but `go list -deps ./...` (which doesn't filter test files) would still traverse it. Using `go list -deps -test=false ./...` more explicitly conveys intent, though the current flag-less form already excludes test builds.
@@ -0,0 +101,4 @@
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)
First-time contributor

[MINOR] The regex "^${test_pkg}(/|\$|$)" has a redundant $\$ escapes the literal dollar sign for the shell but in the regex context inside grep -qE, the trailing |$) is a proper end-of-line anchor followed by the closing group, making \$ (literal $ character) unreachable in practice. This is harmless but the intent (match exact package or subpackage) is already handled by the ^pkg($|/) pattern. Consider simplifying to "^${test_pkg}(/|$)".

**[MINOR]** The regex `"^${test_pkg}(/|\$|$)"` has a redundant `$` — `\$` escapes the literal dollar sign for the shell but in the regex context inside `grep -qE`, the trailing `|$)` is a proper end-of-line anchor followed by the closing group, making `\$` (literal `$` character) unreachable in practice. This is harmless but the intent (match exact package or subpackage) is already handled by the `^pkg($|/)` pattern. Consider simplifying to `"^${test_pkg}(/|$)"`.
gpt-review-bot approved these changes 2026-05-10 21:04:14 +00:00
gpt-review-bot left a comment
First-time contributor

Gpt Review

Summary

The dependency policy update and enforcement script look sound. The Makefile integration is clean, and CI has passed. The new check-deps.sh correctly enforces an allowlist, distinguishes test-only deps, and tolerates subpackages.

Findings

# Severity File Line Finding
1 [MINOR] scripts/check-deps.sh 35 The filter [[ "$pkg" =~ ^[a-zA-Z] ]] rejects valid import paths that begin with a digit (e.g., 9fans.net/go). Consider relaxing to ^[[:alnum:]] or removing the check, since the header row is already excluded by the grep.
2 [MINOR] scripts/check-deps.sh 109 The grep regex `^${test_pkg}(/
3 [NIT] scripts/check-deps.sh 32 Parsing the markdown table with grep/awk is somewhat brittle (e.g., relies on backticks around package names and exact column positions). This is acceptable given the documented process, but a brief note in CONVENTIONS.md to preserve formatting would help avoid accidental breakage.
4 [NIT] Makefile 15 The check-deps script requires Bash 4+. On macOS, default /bin/bash is 3.x; while the script emits guidance, you might consider documenting this requirement alongside the new precommit target for developer setup clarity.

Recommendation

APPROVE — Overall, the changes are well-implemented and align with the updated policy. The allowlist enforcement correctly checks direct module dependencies and prevents test-only packages from being used in production code. Consider relaxing the package-name filter to allow domains that start with digits, simplifying a redundant regex in the production check, and adding a small note about preserving the markdown table format and the Bash 4+ requirement in developer docs. With these minor tweaks, this will be robust and maintainable. Approving as-is.


Review by gpt


Evaluated against 01cde16d

# Gpt Review ## Summary The dependency policy update and enforcement script look sound. The Makefile integration is clean, and CI has passed. The new check-deps.sh correctly enforces an allowlist, distinguishes test-only deps, and tolerates subpackages. ## Findings | # | Severity | File | Line | Finding | |---|----------|------|------|--------| | 1 | [MINOR] | `scripts/check-deps.sh` | 35 | The filter `[[ "$pkg" =~ ^[a-zA-Z] ]]` rejects valid import paths that begin with a digit (e.g., 9fans.net/go). Consider relaxing to `^[[:alnum:]]` or removing the check, since the header row is already excluded by the grep. | | 2 | [MINOR] | `scripts/check-deps.sh` | 109 | The grep regex `^${test_pkg}(/|\$|$)` redundantly includes both `\$` and `$`. It can be simplified to `^${test_pkg}(/|$)` without changing semantics. | | 3 | [NIT] | `scripts/check-deps.sh` | 32 | Parsing the markdown table with `grep`/`awk` is somewhat brittle (e.g., relies on backticks around package names and exact column positions). This is acceptable given the documented process, but a brief note in CONVENTIONS.md to preserve formatting would help avoid accidental breakage. | | 4 | [NIT] | `Makefile` | 15 | The check-deps script requires Bash 4+. On macOS, default /bin/bash is 3.x; while the script emits guidance, you might consider documenting this requirement alongside the new precommit target for developer setup clarity. | ## Recommendation **APPROVE** — Overall, the changes are well-implemented and align with the updated policy. The allowlist enforcement correctly checks direct module dependencies and prevents test-only packages from being used in production code. Consider relaxing the package-name filter to allow domains that start with digits, simplifying a redundant regex in the production check, and adding a small note about preserving the markdown table format and the Bash 4+ requirement in developer docs. With these minor tweaks, this will be robust and maintainable. Approving as-is. --- *Review by gpt* <!-- review-bot:gpt --> --- *Evaluated against 01cde16d*
@@ -12,9 +12,15 @@ test-integration:
lint:
go vet ./...
check-deps:
First-time contributor

[NIT] The check-deps script requires Bash 4+. On macOS, default /bin/bash is 3.x; while the script emits guidance, you might consider documenting this requirement alongside the new precommit target for developer setup clarity.

**[NIT]** The check-deps script requires Bash 4+. On macOS, default /bin/bash is 3.x; while the script emits guidance, you might consider documenting this requirement alongside the new precommit target for developer setup clarity.
@@ -0,0 +29,4 @@
declare -A ALLOWED_TEST=()
while IFS= read -r line; do
# Use awk to extract package and scope from table row
First-time contributor

[NIT] Parsing the markdown table with grep/awk is somewhat brittle (e.g., relies on backticks around package names and exact column positions). This is acceptable given the documented process, but a brief note in CONVENTIONS.md to preserve formatting would help avoid accidental breakage.

**[NIT]** Parsing the markdown table with `grep`/`awk` is somewhat brittle (e.g., relies on backticks around package names and exact column positions). This is acceptable given the documented process, but a brief note in CONVENTIONS.md to preserve formatting would help avoid accidental breakage.
@@ -0,0 +32,4 @@
# 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)}')
First-time contributor

[MINOR] The filter [[ "$pkg" =~ ^[a-zA-Z] ]] rejects valid import paths that begin with a digit (e.g., 9fans.net/go). Consider relaxing to ^[[:alnum:]] or removing the check, since the header row is already excluded by the grep.

**[MINOR]** The filter `[[ "$pkg" =~ ^[a-zA-Z] ]]` rejects valid import paths that begin with a digit (e.g., 9fans.net/go). Consider relaxing to `^[[:alnum:]]` or removing the check, since the header row is already excluded by the grep.
@@ -0,0 +106,4 @@
TEST_ONLY_IN_PROD=""
for test_pkg in "${!ALLOWED_TEST[@]}"; do
# Use word-boundary matching: exact match or followed by /
First-time contributor

[MINOR] The grep regex ^${test_pkg}(/|\$|$) redundantly includes both \$ and $. It can be simplified to ^${test_pkg}(/|$) without changing semantics.

**[MINOR]** The grep regex `^${test_pkg}(/|\$|$)` redundantly includes both `\$` and `$`. It can be simplified to `^${test_pkg}(/|$)` without changing semantics.
security-review-bot requested review from security-review-bot 2026-05-10 21:04:15 +00:00
security-review-bot approved these changes 2026-05-10 21:04:15 +00:00
security-review-bot left a comment
Collaborator

Security Review

Summary

Changes introduce a strict dependency allowlist with an enforcement script and integrate it into the precommit workflow. CI passed and the additions do not introduce exploitable vulnerabilities.

Recommendation

APPROVE — The new policy and check-deps script strengthen supply-chain controls by enforcing an explicit allowlist and test-only constraints. Consider future hardening (e.g., escaping regex metacharacters in grep patterns and tightening the Bash version check for namerefs), but these are not security-critical. Proceed with merge.


Review by security


Evaluated against 01cde16d

# Security Review ## Summary Changes introduce a strict dependency allowlist with an enforcement script and integrate it into the precommit workflow. CI passed and the additions do not introduce exploitable vulnerabilities. ## Recommendation **APPROVE** — The new policy and check-deps script strengthen supply-chain controls by enforcing an explicit allowlist and test-only constraints. Consider future hardening (e.g., escaping regex metacharacters in grep patterns and tightening the Bash version check for namerefs), but these are not security-critical. Proceed with merge. --- *Review by security* <!-- review-bot:security --> --- *Evaluated against 01cde16d*
rodin added the wip label 2026-05-10 21:05:44 +00:00
rodin merged commit fededd18ad into main 2026-05-10 21:07:10 +00:00
Author
Owner

Review Feedback Addressed

Pushed commit 0619e2b with the following changes:

Fixed (5 findings)

  1. [MINOR] Line 35 - import path filter (sonnet + gpt): Relaxed ^[a-zA-Z] to ^[[:alnum:]] to accept valid paths starting with digits (e.g., 9fans.net/go).

  2. [MINOR] Line 99/109 - redundant \$ in regex (sonnet + gpt): Simplified ^${test_pkg}(/|\$|$) to ^${test_pkg}(/|$) — the \$ (literal dollar) was unreachable.

  3. [MINOR] Line 71 - stderr mixing (sonnet): Now captures stderr to a temp file to avoid mixing error messages with package list output.

  4. [NIT] Line 26 comment (sonnet): Updated misleading "POSIX-compatible" comment — the loop uses Bash process substitution < <(...).

  5. [NIT] CONVENTIONS.md line 17 (sonnet): Clarified wording: "Only direct dependencies (listed in go.mod without // indirect) are checked against this allowlist. Transitive dependencies pulled in by approved packages are implicitly allowed."

Deferred (2 findings)

  • Markdown table parsing brittleness (gpt NIT): The existing note in CONVENTIONS.md already warns that the script parses the table. Additional documentation provides low value.

  • Bash 4+ macOS documentation (gpt NIT): The script already has a runtime check with clear error message and instructions (brew install bash). Duplicating in Makefile is redundant.

All tests pass: go test ./...

## Review Feedback Addressed Pushed commit `0619e2b` with the following changes: ### Fixed (5 findings) 1. **[MINOR] Line 35 - import path filter** (sonnet + gpt): Relaxed `^[a-zA-Z]` to `^[[:alnum:]]` to accept valid paths starting with digits (e.g., `9fans.net/go`). 2. **[MINOR] Line 99/109 - redundant `\$` in regex** (sonnet + gpt): Simplified `^${test_pkg}(/|\$|$)` to `^${test_pkg}(/|$)` — the `\$` (literal dollar) was unreachable. 3. **[MINOR] Line 71 - stderr mixing** (sonnet): Now captures stderr to a temp file to avoid mixing error messages with package list output. 4. **[NIT] Line 26 comment** (sonnet): Updated misleading "POSIX-compatible" comment — the loop uses Bash process substitution `< <(...)`. 5. **[NIT] CONVENTIONS.md line 17** (sonnet): Clarified wording: "Only *direct* dependencies (listed in go.mod without `// indirect`) are checked against this allowlist. Transitive dependencies pulled in by approved packages are implicitly allowed." ### Deferred (2 findings) - **Markdown table parsing brittleness** (gpt NIT): The existing note in CONVENTIONS.md already warns that the script parses the table. Additional documentation provides low value. - **Bash 4+ macOS documentation** (gpt NIT): The script already has a runtime check with clear error message and instructions (`brew install bash`). Duplicating in Makefile is redundant. All tests pass: `go test ./...` ✅
rodin removed the wip label 2026-05-10 21:11:03 +00:00
Sign in to join this conversation.
4 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: rodin/review-bot#59