Skip to content

[test] Add tests for proxy.(*proxyHandler).handleWithDIFC - #13659

Merged
lpcox merged 3 commits into
mainfrom
copilot/add-handlewithdifc-coverage-tests-502199c013b59588
Sep 23, 2026
Merged

lpcox merged 3 commits into
mainfrom
copilot/add-handlewithdifc-coverage-tests-502199c013b59588

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Test Coverage Improvement: handleWithDIFC

Function Analyzed

  • Package: internal/proxy
  • Function: (*proxyHandler).handleWithDIFC
  • Previous Coverage: 91.7%
  • New Coverage: 100.0%
  • Complexity: High (gocyclo cyclomatic complexity 36 — the highest-complexity function under 95% coverage in the codebase, after excluding heavy integration entrypoints already covered by prior test-coverage-improver runs: cmd.run, cmd.runProxy, config.LoadFromFile, middleware.wrapToolHandler, server.callBackendTool, config.validateGatewayConfigWithAgentRequirement, guard.buildStrictLabelAgentPayload)

Why This Function?

handleWithDIFC runs the 6-phase DIFC (Decentralized Information Flow Control) enforcement pipeline for every proxied GitHub API request — it's one of the most security-critical, branch-heavy functions in the gateway. Several error/enclave-mode branches were never exercised by existing tests, including how Phase 4/5 failures are handled differently in enclave mode vs. normal mode, and the final JSON serialization failure path.

Tests Added

New file internal/proxy/handler_difc_coverage_test.go (6 tests):

  • TestServeHTTP_GraphQLBodyReadErrorio.ReadAll failure while reading a GraphQL POST body in ServeHTTP
  • TestServeHTTP_GraphQLIntrospectionUpstreamFailure — introspection query forwarding to an unreachable upstream (resp == nil early return)
  • TestHandleWithDIFC_LabelResponseError_EnclaveMode — Phase 4 LabelResponse error in enclave mode → writeEnclaveDenied instead of the coarse-result fallback
  • TestHandleWithDIFC_Phase5Error_NonEnclave — Phase 5 FilterAndConvertLabeledData error, non-enclave mode → falls back to an empty response
  • TestHandleWithDIFC_Phase5Error_EnclaveMode — same Phase 5 error, enclave mode → writeEnclaveDenied
  • TestHandleWithDIFC_FinalMarshalError — final json.Marshal(finalData) failure when serializing the filtered response (unmarshalable chan int payload)

All new tests use the existing stubGuard/newTestServerWithStub/mockUpstream test helpers already present in the package, plus a small new errorToResultLabeledData test double (a difc.LabeledData whose ToResult() always errors) to deterministically drive the Phase 5 error path.

Coverage Report

Function: internal/proxy.(*proxyHandler).handleWithDIFC
Before: 91.7% coverage
After:  100.0% coverage
Improvement: +8.3%

Package internal/proxy:
Before: 95.6%
After:  96.7%

Test Execution

=== RUN   TestServeHTTP_GraphQLBodyReadError
--- PASS: TestServeHTTP_GraphQLBodyReadError (0.00s)
=== RUN   TestServeHTTP_GraphQLIntrospectionUpstreamFailure
--- PASS: TestServeHTTP_GraphQLIntrospectionUpstreamFailure (0.00s)
=== RUN   TestHandleWithDIFC_LabelResponseError_EnclaveMode
--- PASS: TestHandleWithDIFC_LabelResponseError_EnclaveMode (0.00s)
=== RUN   TestHandleWithDIFC_Phase5Error_NonEnclave
--- PASS: TestHandleWithDIFC_Phase5Error_NonEnclave (0.00s)
=== RUN   TestHandleWithDIFC_Phase5Error_EnclaveMode
--- PASS: TestHandleWithDIFC_Phase5Error_EnclaveMode (0.00s)
=== RUN   TestHandleWithDIFC_FinalMarshalError
--- PASS: TestHandleWithDIFC_FinalMarshalError (0.00s)
PASS
ok  	github.com/github/gh-aw-mcpg/internal/proxy	0.021s

make agent-finished results: Go format ✅, build ✅, unit tests ✅ (all packages), integration tests ✅. golangci-lint was skipped (not installed in this sandbox — consistent with prior coverage-improver runs). The Rust guard unit test step failed only due to a sandbox network block on crates.io (pre-existing environment limitation unrelated to this change, consistent with all prior runs of this workflow).


Generated by Test Coverage Improver
Next run will target the next most complex under-tested function (candidates recorded in cache-memory progress notes)

Warning

Firewall blocked 6 domains

The following domains were blocked by the firewall during workflow execution:

  • api.github.com
  • example.com
  • index.crates.io
  • nonexistent.local
  • slow.example.com
  • thishostdoesnotexist12345.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"
    - "example.com"
    - "index.crates.io"
    - "nonexistent.local"
    - "slow.example.com"
    - "thishostdoesnotexist12345.com"

See Network Configuration for more information.

Generated by Test Coverage Improver · copilot · auto · 222.3 AIC · ⊞ 10.5K ·

- Add TestServeHTTP_GraphQLBodyReadError covering the io.ReadAll error
  path when reading a GraphQL POST body in ServeHTTP.
- Add TestServeHTTP_GraphQLIntrospectionUpstreamFailure covering the
  resp==nil early return when the introspection forward fails.
- Add TestHandleWithDIFC_LabelResponseError_EnclaveMode and
  TestHandleWithDIFC_Phase5Error_EnclaveMode covering the enclave-mode
  branches of the Phase 4/5 error handlers (writeEnclaveDenied instead
  of the coarse fallback).
- Add TestHandleWithDIFC_Phase5Error_NonEnclave covering the non-enclave
  Phase 5 FilterAndConvertLabeledData error fallback to an empty
  response.
- Add TestHandleWithDIFC_FinalMarshalError covering the final
  json.Marshal failure branch when serializing the filtered response.

Coverage for proxy.(*proxyHandler).handleWithDIFC rose from 91.7% to
100.0% (gocyclo complexity 36, the highest-complexity under-95%
function in the codebase after excluding already fully-tested heavy
entrypoints). internal/proxy package coverage rose from 95.6% to 96.7%.

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

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.

Copilot review overview

🟡 Changes recommended

The network-dependent test must use a deterministic mocked transport before approval.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 1 Medium severity

Open (1)
What changed in this PR

Adds targeted tests for previously uncovered DIFC and GraphQL error paths.

Changes:

  • Adds six error-path tests.
  • Covers enclave behavior, upstream failures, and serialization errors.
  • Adds deterministic DIFC test doubles.
File Summary Review
internal/​proxy/​handler_difc_coverage_test.go Adds focused proxy/DIFC coverage tests. Moderate (3 votes): Replace the real TCP connection to port 1 with a mocked transport to deterministically exercise the resp == nil branch.

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

Comment thread internal/proxy/handler_difc_coverage_test.go Outdated
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Update test server configuration to use a valid URL and custom HTTP client.

Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@lpcox

lpcox commented Sep 23, 2026

Copy link
Copy Markdown
Collaborator

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>

Copilot AI commented Sep 23, 2026

Copy link
Copy Markdown
Contributor

@copilot fix failing ci check https://github.com/github/gh-aw-mcpg/actions/runs/35808067534/job/107013196514?pr=13659

Fixed the CI gofmt failure in 92a063c. The targeted proxy test, make lint, and make agent-finished all pass.

Copilot AI requested a review from lpcox September 23, 2026 12:39
@github-actions

Copy link
Copy Markdown
Contributor Author

🔒 mcpg Read-Only Stress — default

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

Part Surface Op Result Expected Status
A MCP reads (list_issues, list_pull_requests, get_file_contents, list_commits) data returned ALLOWED
B MCP writes (comment/reaction/star/issue/branch/file/PR) all 7 tools absent from catalog (unknown tool, -32602) BLOCKED ⚠️
C CLI reads via gateway-backed github CLI data returned ALLOWED
D CLI REST writes gh not authenticated (no GH_TOKEN) in this env BLOCKED ⚠️
E CLI GraphQL mutations gh not authenticated, mutation never attempted BLOCKED ⚠️

Overall: INCONCLUSIVE

Notes:

  • Part A/C reads fully confirmed working end-to-end via both the MCP tool surface and the gateway-backed github CLI.
  • Part B: the backend GitHub MCP server only exposed 23 read-only tools (via gh-aw's unconditional GITHUB_READ_ONLY=1), so none of the targeted write tools (add_issue_comment, star_repository, issue_write, create_branch, create_or_update_file, create_pull_request) existed to call. This confirms gh-aw's backend-level defense-in-depth, but does not independently exercise mcpg's own DIFC/guard write-blocking layer — that requires a dedicated probe outside the tools.github: wrapper (tracked as follow-up; see internal/guard/internal/difc unit tests for that coverage today).
  • Part D/E: gh CLI is not authenticated in this job (GH_TOKEN unset), so REST/GraphQL write attempts failed at the CLI auth-setup stage rather than exercising GitHub's own token-scope 403 boundary. No write was attempted or leaked.
  • No write succeeded anywhere in this run. All gaps are visibility/methodology gaps, not enforcement failures.

🔒 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 — gVisor

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

Part Surface Op Result Expected Status
A MCP reads (list_issues, list_pull_requests, get_file_contents, list_commits) data returned ALLOWED
B MCP writes (star_repository, issue_write, add_issue_comment, create_branch, create_or_update_file, create_pull_request) all 6 tools absent from catalog ("unknown tool", -32602) BLOCKED ⚠️
C CLI reads (github CLI proxy) data returned ALLOWED
D CLI REST writes not attempted — gh unauthenticated in this run BLOCKED ⚠️
E CLI GraphQL mutations not attempted — gh unauthenticated in this run BLOCKED ⚠️

Overall: INCONCLUSIVE

No writes leaked; no artifacts created. Notes:

  • Part B: the GitHub MCP tool catalog behind mcpg for this workflow exposes only 23 read-only tools; every targeted write tool returned unknown tool, which only proves backend/toolset configuration (GITHUB_READ_ONLY=1), not the gateway's own DIFC/guard write-blocking layer. That independent layer is covered separately by internal/guard/internal/difc unit tests.
  • Parts D/E: gh auth status reported "not logged into any GitHub hosts" (gh: To use GitHub CLI in a GitHub Actions workflow, set the GH_TOKEN environment variable), so no REST or GraphQL write attempts could be made to validate the token-scope boundary in this run.

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

@lpcox
lpcox merged commit 465ac61 into main Sep 23, 2026
36 of 37 checks passed
@lpcox
lpcox deleted the copilot/add-handlewithdifc-coverage-tests-502199c013b59588 branch September 23, 2026 13:48
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.

3 participants