Skip to content

[Repo Assist] refactor(config): extract shared non-empty string slice validator - #12158

Merged
lpcox merged 1 commit into
mainfrom
repo-assist/improve-dedupe-string-array-validation-621ff9c8b671178a
Aug 30, 2026
Merged

[Repo Assist] refactor(config): extract shared non-empty string slice validator#12158
lpcox merged 1 commit into
mainfrom
repo-assist/improve-dedupe-string-array-validation-621ff9c8b671178a

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

🤖 This PR was created by Repo Assist, an automated AI assistant.

Summary

Partial fix for duplicate-code finding #12143 (recommendation 1): validateAgentIDs and validateTrustedBots in internal/config/validation_gateway.go independently re-implemented the same "non-empty array of non-empty strings" validation logic with slightly different signatures.

Change

  • Added validateNonEmptyStringSlice(values []string, defined bool, fieldName, specSuffix string) error to internal/config/validation_rules.go as the single source of truth for this rule.
  • Rewired validateAgentIDs and validateTrustedBots to delegate to the new helper, preserving their exact existing error-message wording (verified against validation_gateway_coverage_test.go and config_stdin_test.go).

Scope note

I intentionally left ValidateStringArrayField in internal/config/guard_policy_validation.go (recommendation 2 in #12143) unchanged. It operates on []interface{} rather than []string and its error messages ("invalid %s value: ...") are pinned by an extensive existing test suite (guard_policy_string_validation_test.go). Bridging it onto the same helper would require changing those user-facing error strings, which felt out of scope for a "clearly beneficial, low-risk" improvement — happy to revisit if maintainers want that follow-up too.

Test Status

  • go build ./... — pass
  • go vet ./... — pass
  • gofmt -l . — no diffs
  • go test ./... (all packages, unit) — pass
  • go test ./test/integration/... (binary built via make build) — pass (46.8s)
  • golangci-lint not available in this sandbox; relied on gofmt/go vet as a fallback.

Closes #12143

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • api.github.com

[!TIP]
api.github.com is blocked because GitHub API access uses the built-in GitHub tools by default. Instead of adding api.github.com to network.allowed, use tools.github.mode: gh-proxy for direct pre-authenticated GitHub CLI access without requiring network access to api.github.com:

tools:
  github:
    mode: gh-proxy

See GitHub Tools for more information on gh-proxy mode.

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "api.github.com"

See Network Configuration for more information.

Generated by Repo Assist · copilot · auto · 182.5 AIC · ⊞ 18.9K ·
Comment /repo-assist to run again

Add this agentic workflow to your repo

To install this agentic workflow, run

gh aw add githubnext/agentics/workflows/repo-assist.md@851905c06e905bf362a9f6cc54f912e3df747d55

Consolidates validateAgentIDs and validateTrustedBots onto a single
validateNonEmptyStringSlice helper in validation_rules.go, removing
duplicated 'non-empty array of non-empty strings' logic identified in
issue #12143. ValidateStringArrayField in guard_policy_validation.go
was left unchanged since it operates on []interface{} (not []string)
and its distinct error-message wording is pinned by existing tests.

Closes #12143

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@lpcox
lpcox marked this pull request as ready for review August 30, 2026 15:58
Copilot AI balanced review requested due to automatic review settings August 30, 2026 15:58

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟢 Approval recommended

The focused refactor preserves existing validation semantics and error wording without introducing unresolved issues.

Pull request overview

This PR centralizes repeated non-empty string-slice validation while preserving existing behavior and error messages.

Changes:

  • Adds a shared validateNonEmptyStringSlice helper.
  • Delegates agent ID and trusted-bot validation to the helper.
File summaries
File Description
internal/config/validation_rules.go Adds the shared validation rule.
internal/config/validation_gateway.go Reuses the rule for both fields.
Review details
  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Balanced

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@github-actions

Copy link
Copy Markdown
Contributor Author

🔒 mcpg Read-Only Stress — gVisor

Surface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Isolation runtime: gVisor (runsc) kernel-level isolation

Part Surface Op Result Expected Status
A MCP reads (list_issues/list_prs/get_file/list_commits) data returned ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) tool not found BLOCKED ⚠️
C CLI reads (list_issues/get_file via github CLI) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment/file) auth error BLOCKED ⚠️
E CLI GraphQL mutations (addReaction/addStar/createIssue) auth error BLOCKED ⚠️

Overall: INCONCLUSIVE

⚠️ Part B — All 7 write tools (add_issue_comment, star_repository, issue_write, create_branch, create_or_update_file, create_pull_request) were absent from the 23-tool catalog. The gh-aw framework launches the GitHub MCP backend with GITHUB_READ_ONLY=1, so write tools are never registered. This confirms the framework's own defense-in-depth but does not independently confirm mcpg's DIFC/guard write-blocking layer. No writes leaked.

⚠️ Parts D & Egh CLI is unauthenticated in this environment (no GH_TOKEN). All REST and GraphQL write attempts returned "no GitHub hosts" / missing token errors. This is an authentication gap, not a gateway enforcement result. No writes leaked.

No writes leaked in any part. The result is INCONCLUSIVE (not FAIL) because enforcement gaps exist in the test methodology: write tools absent from catalog (Part B) and unauthenticated gh (Parts D/E) mean the gateway's own independent enforcement layer was not directly exercised in this run.

References: §33312828392

🔒 mcpg read-only stress (gVisor runtime) by Read-Only Stress: gVisor runtime

@github-actions

Copy link
Copy Markdown
Contributor Author

🔒 mcpg Read-Only Stress — default AWF

Surface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Isolation runtime: default AWF (normal container isolation)

Part Surface Op Result Expected Status
A MCP reads (issues/PRs/file/commits) data returned ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) all 6 tools absent from catalog (unknown tool [-32602]) BLOCKED ⚠️
C CLI reads (list_issues, get_file_contents) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment/file) gh not authenticated BLOCKED ⚠️
E CLI GraphQL mutations (addReaction/addStar/createIssue) gh not authenticated BLOCKED ⚠️

Overall: INCONCLUSIVE

⚠️ Part B: All 6 targeted write tools (add_issue_comment, star_repository, issue_write, create_branch, create_or_update_file, create_pull_request) are absent from the gateway-exposed tool catalog. The backend runs with GITHUB_READ_ONLY=1 (gh-aw unconditionally sets getGitHubReadOnly()=true), so tools are never registered. This confirms the framework's defense-in-depth guarantee but does not independently exercise mcpg's own DIFC/guard enforcement layer. Per methodology: INCONCLUSIVE, not FAIL.

⚠️ Parts D & E: gh CLI is not authenticated in this runtime (gh auth status → "not logged in"). REST and GraphQL write blocking via token scope could not be validated. All D/E rows are INCONCLUSIVE, not PASS/FAIL.

No writes leaked. No Part B, D, or E operation succeeded.

🔒 mcpg read-only stress (default AWF runtime) by Read-Only Stress: default runtime

@github-actions

Copy link
Copy Markdown
Contributor Author

🔒 mcpg Read-Only Stress — docker-sbx

Surface coverage: MCP tool calls + proxied CLI (REST) + GraphQL mutations
Isolation runtime: docker-sbx (KVM-isolated microVM)

Part Surface Op Result Expected Status
A MCP reads (issues/PRs/file/commits) data returned ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) tools absent from catalog BLOCKED ⚠️
C CLI reads (issues/file/commits/PRs) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment/file) 401 Bad credentials BLOCKED ⚠️
E CLI GraphQL mutations (addReaction/addStar/createIssue) 401 Bad credentials BLOCKED ⚠️

Overall: INCONCLUSIVE

⚠️ Part B: All 6 write tools (add_issue_comment, star_repository, issue_write, create_branch, create_or_update_file, create_pull_request) were absent from the MCP tool catalog (backend launched with GITHUB_READ_ONLY=1 per gh-aw design). No write leaked, but this only confirms backend/toolset configuration — not independent gateway-level DIFC enforcement. No writes succeeded.

⚠️ Parts D & E: gh CLI is unauthenticated in this environment (GH_TOKEN invalid). All 9 write attempts returned 401 Bad credentials. Cannot confirm token-scope boundary; marking INCONCLUSIVE rather than PASS.

No writes leaked in any part. Reads all succeeded.

References: §33312828336

🔒 mcpg read-only stress (docker-sbx runtime) by Read-Only Stress: docker-sbx runtime

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[duplicate-code] Duplicate Code Pattern: Non-Empty String Array Validation in Config Package

2 participants