Skip to content

refactor(config): add validateOptionalInt to eliminate repeated nil-guard boilerplate#10059

Merged
lpcox merged 2 commits into
mainfrom
copilot/duplicate-code-validation-guard
Jul 25, 2026
Merged

refactor(config): add validateOptionalInt to eliminate repeated nil-guard boilerplate#10059
lpcox merged 2 commits into
mainfrom
copilot/duplicate-code-validation-guard

Conversation

Copilot AI commented Jul 25, 2026

Copy link
Copy Markdown
Contributor

The config validation code repeated the same nil-check-before-dereference pattern ~5 times across validation_gateway.go and validation_server.go, with no shared abstraction — increasing bug risk (forgetting the nil guard on new fields) and making the validation functions harder to scan.

Changes

  • validation_rules.go — Adds validateOptionalInt(ptr *int, logMsg string, validateFn func(int) *ValidationError) error. Explicitly checks *ValidationError != nil before returning as error to avoid the typed-nil-interface pitfall.

  • validation_gateway.go — Replaces 4 nil-guarded blocks (Port, StartupTimeout, ToolTimeout, PayloadSizeThreshold) with validateOptionalInt calls.

  • validation_server.go — Replaces the per-server ToolTimeout nil-guard. The zero-means-inherit sentinel is handled inside the closure, preserving existing semantics.

  • validation_rules_test.go — Adds TestValidateOptionalInt covering: nil ptr (no-op), valid value, invalid value, closure with zero-sentinel guard.

Example

// Before (repeated ~5×):
if gateway.StartupTimeout != nil {
    logValidation.Printf("Validating startup timeout: %d", *gateway.StartupTimeout)
    if err := TimeoutPositive(*gateway.StartupTimeout, "startupTimeout", "gateway.startupTimeout"); err != nil {
        return err
    }
}

// After:
if err := validateOptionalInt(gateway.StartupTimeout, "Validating startup timeout",
    func(v int) *ValidationError { return TimeoutPositive(v, "startupTimeout", "gateway.startupTimeout") }); err != nil {
    return err
}

Adding a new optional *int field now requires a single validateOptionalInt call rather than a copy-pasted nil-guard block.

…rd duplication

Adds a generic `validateOptionalInt(ptr *int, logMsg string, validateFn func(int) *ValidationError) error` helper to `internal/config/validation_rules.go` that consolidates the repeated nil-check-before-dereference pattern for optional `*int` fields in config validation.

- Correctly handles the Go nil-interface pitfall: the `*ValidationError` return from `validateFn` is checked for nil before being returned as `error`.
- Refactors `validateGatewayConfig` (4 occurrences) and `validateStandardServerConfig` (1 occurrence) to use the helper.
- The zero-sentinel case in per-server `toolTimeout` (0 means inherit from gateway) is handled inline in the closure, preserving existing semantics.
- Adds `TestValidateOptionalInt` covering nil pointer, valid value, invalid value, and the zero-sentinel guard pattern.

Closes #10044
Copilot AI changed the title [WIP] Refactor duplicate code pattern for optional pointer field validation refactor(config): add validateOptionalInt to eliminate repeated nil-guard boilerplate Jul 25, 2026
Copilot finished work on behalf of lpcox July 25, 2026 14:36
Copilot AI requested a review from lpcox July 25, 2026 14:36
@lpcox
lpcox marked this pull request as ready for review July 25, 2026 14:47
Copilot AI review requested due to automatic review settings July 25, 2026 14:47

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.

Pull request overview

Refactors optional integer validation to centralize nil guarding while preserving existing validation semantics.

Changes:

  • Adds and tests validateOptionalInt.
  • Refactors gateway and per-server integer validation to use the helper.
  • Preserves per-server zero-as-inherit behavior.
Show a summary per file
File Description
internal/config/validation_rules.go Adds the shared validation helper.
internal/config/validation_rules_test.go Tests nil, valid, invalid, and sentinel cases.
internal/config/validation_gateway.go Refactors four optional gateway fields.
internal/config/validation_server.go Refactors per-server tool timeout validation.

Review details

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 4/4 changed files
  • Comments generated: 0
  • Review effort level: Medium

@github-actions

Copy link
Copy Markdown
Contributor

🔒 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 (issues/PRs/file/commits) data returned ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) gateway refused all 7 (Error[-32602]: unknown tool; absent from manifest; ~7ms = gateway-level) BLOCKED
C CLI reads (list_issues, get_file_contents) data returned ALLOWED
D CLI REST writes (6 attempts) blocked — gh unauthenticated (no GH_TOKEN) BLOCKED
E CLI GraphQL mutations (addReaction/addStar/createIssue) blocked — gh unauthenticated (no GH_TOKEN) BLOCKED

Gateway enforcement note: Write MCP tools are entirely absent from the gateway tool manifest (github.json). Refusals arrive in ~7ms without reaching the backend, confirming gateway-level enforcement (not merely backend config).

Overall: PASS

References: §30161934639

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

@github-actions

Copy link
Copy Markdown
Contributor

🔒 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 (list_issues/PRs/commits, get_file_contents) data returned ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) gateway refused — write tools not registered (Error[-32602]: unknown tool) BLOCKED
C CLI reads (list_issues, get_file_contents via github CLI) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment/file) rejected — gh unauthenticated (no GH_TOKEN) BLOCKED
E CLI GraphQL mutations (addReaction/addStar/createIssue) rejected — gh unauthenticated (no GH_TOKEN) BLOCKED

Gateway enforcement note: tools.json confirms gateway registers only read-only tools for the github MCP server. Write tools (star_repository, add_issue_reaction, create_branch, create_or_update_file, create_pull_request) are absent — gateway-level policy enforcement, not merely backend configuration.

Overall: PASS

References: §30161934629

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

@github-actions

Copy link
Copy Markdown
Contributor

🔒 mcpg Read-Only Stress — default

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 (list_issues, list_prs, get_file, list_commits) data returned ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) Error[-32602]: unknown tool (gateway MCP error, <21ms, no backend round-trip) BLOCKED
C CLI reads (list_issues, get_file_contents) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment/file) gh unauthenticated — exit 4, all rejected BLOCKED
E CLI GraphQL mutations (addReaction/addStar/createIssue) gh unauthenticated — exit 4, all rejected BLOCKED

Gateway enforcement detail (Part B): All 7 write tools absent from the 22-tool read-only registry. Gateway returns MCP JSON-RPC -32602 in <21ms — no backend round-trip, confirming gateway-level enforcement (not just backend config).

Overall: PASS

References: §30161934628

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

@lpcox
lpcox merged commit 4bb58d1 into main Jul 25, 2026
45 checks passed
@lpcox
lpcox deleted the copilot/duplicate-code-validation-guard branch July 25, 2026 15:03
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: Optional Pointer Field Validation Guard in Config

3 participants