Skip to content

[test] Add tests for server.createGuardFromConfig and requireGuardPolicyIfGuardEnabled - #12110

Merged
lpcox merged 3 commits into
mainfrom
test-coverage-guard-init-1788021445-6da78314cfc50244
Aug 30, 2026
Merged

[test] Add tests for server.createGuardFromConfig and requireGuardPolicyIfGuardEnabled#12110
lpcox merged 3 commits into
mainfrom
test-coverage-guard-init-1788021445-6da78314cfc50244

Conversation

@github-actions

Copy link
Copy Markdown
Contributor

Test Coverage Improvement: createGuardFromConfig and requireGuardPolicyIfGuardEnabled

Functions Analyzed

  • Package: internal/server
  • Functions: UnifiedServer.createGuardFromConfig, UnifiedServer.requireGuardPolicyIfGuardEnabled
  • Previous Coverage: 81.8% and 84.6% respectively
  • New Coverage: 100% (both)
  • Complexity: Medium-High — both functions have multiple conditional branches with distinct guard-initialization outcomes (noop fallback, WASM guard creation/failure, policy resolution, error propagation).

Why These Functions?

go tool cover -func showed internal/server/guard_init.go had two functions with meaningful uncovered branches directly relevant to the gateway's security-critical guard/DIFC initialization path:

  • createGuardFromConfig's "wasm" case had a completely uncovered success path (0% coverage on the lines where guard.NewWasmGuard succeeds, logger.LogInfo is called, and the guard + nil error are returned). Existing tests only covered the empty-path and invalid-WASM-file error branches.
  • requireGuardPolicyIfGuardEnabled had an uncovered branch where a server has non-empty GuardPolicies that doesn't parse into a structured *config.GuardPolicy yet (e.g. an unrecognized key) — this must keep the non-noop guard for later DIFC resolution rather than falling back to noop, and this specific case wasn't exercised.

Both functions gate whether backend requests get labeled/guarded at all, so covering their success/edge branches closes a real correctness-verification gap.

Tests Added

  • TestCreateGuardFromConfig_WasmType_Success — loads a minimal valid WASM module (exporting label_resource, label_response, label_agent, memory) from a temp file and verifies createGuardFromConfig returns a working guard with a nil error.
  • TestCreateGuardFromConfig_WasmType_Success_ViaRegisterGuard — exercises the same success path end-to-end through registerGuard, confirming the WASM guard is registered (not replaced by noop).
  • TestRequireGuardPolicyIfGuardEnabled_WithUnparseableGuardPolicies — configures a server with a non-empty but unrecognized GuardPolicies map and verifies the non-noop guard is kept (not downgraded to noop), matching the documented "DIFC will be auto-enabled later" behavior.

Coverage Report

Before:
  createGuardFromConfig                 81.8%
  requireGuardPolicyIfGuardEnabled      84.6%
After:
  createGuardFromConfig                 100.0%
  requireGuardPolicyIfGuardEnabled      100.0%

Test Execution

=== RUN   TestCreateGuardFromConfig_WasmType_Success
--- PASS: TestCreateGuardFromConfig_WasmType_Success (0.00s)
=== RUN   TestCreateGuardFromConfig_WasmType_Success_ViaRegisterGuard
--- PASS: TestCreateGuardFromConfig_WasmType_Success_ViaRegisterGuard (0.00s)
=== RUN   TestRequireGuardPolicyIfGuardEnabled_WithUnparseableGuardPolicies
--- PASS: TestRequireGuardPolicyIfGuardEnabled_WithUnparseableGuardPolicies (0.00s)
PASS
ok  	github.com/github/gh-aw-mcpg/internal/server	0.022s

Full internal/... suite (go test ./internal/...) passes with no regressions; go build ./... and gofmt -l are clean on the modified files.


Generated by Test Coverage Improver
Next run will target the next most complex under-tested function

Generated by Test Coverage Improver · auto · 156.8 AIC · ⊞ 10.6K ·

…ardEnabled

Cover the previously untested WASM success path in createGuardFromConfig
(valid module load, guard creation, logger.LogInfo call) and the
guard-policies-configured-but-unparseable branch in
requireGuardPolicyIfGuardEnabled (keeps non-noop guard for later DIFC
resolution instead of falling back to noop).

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

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.

🟡 Changes recommended

Both WASM success tests leave their wazero runtimes open.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Adds coverage for guard policy fallback and successful WASM guard initialization.

Changes:

  • Tests retention of guards with unrecognized policy maps.
  • Tests direct and registered WASM guard creation.
File summaries
File Description
internal/server/require_guard_policy_test.go Covers unparseable guard policies.
internal/server/register_guard_test.go Covers successful WASM initialization paths.
Review details

Suppressed comments (1)

internal/server/register_guard_test.go:616

  • This second successful WASM instantiation also needs cleanup. Otherwise the registered guard's wazero module/runtime remains open for the rest of the test process; close it through the concrete guard (or close the registry in cleanup).
	require.NoError(t, err)
	registeredGuard := us.guardRegistry.Get("github")
	require.NotNil(t, registeredGuard)
	assert.Equal(t, "wasm-guard", registeredGuard.Name())
  • Files reviewed: 2/2 changed files
  • Comments generated: 1
  • Review effort level: Balanced

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

Comment thread internal/server/register_guard_test.go
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

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.

@github-actions

This comment has been minimized.

@lpcox

lpcox commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

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

Copilot AI commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

@copilot fix failing lint ci check https://github.com/github/gh-aw-mcpg/actions/runs/33269487271/job/99145276187?pr=12110

Fixed the formatting in internal/server/register_guard_test.go and verified that make lint and make agent-finished pass cleanly in 57fd06d.

Copilot AI requested a review from lpcox August 30, 2026 16:05
@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 (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 (list_issues via github CLI) data returned ALLOWED
D CLI REST writes gh unauthenticated BLOCKED ⚠️
E CLI GraphQL mutations gh unauthenticated BLOCKED ⚠️

Overall: INCONCLUSIVE

⚠️ Part B gap: Backend is launched with GITHUB_READ_ONLY=1 (gh-aw framework); all 7 write tools are absent from the 23-tool catalog. "Tool not found" only proves backend config, not mcpg's own DIFC/guard layer. Gateway-level write enforcement cannot be independently confirmed via this surface on any gh-aw run.

⚠️ Parts D/E gap: gh CLI is not authenticated (GH_TOKEN not set in this workflow). Token-scope write-blocking and GraphQL mutation blocking cannot be validated. All D/E results are inconclusive, not PASS/FAIL.

No writes leaked. Result file: RESULT=INCONCLUSIVE RUNTIME=gvisor RUNID=33321440577

References: §33321440577

🔒 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 (normal container isolation)

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

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) unknown tool BLOCKED ⚠️
C CLI reads (list_issues, get_file_contents) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment/file) gh unauthenticated BLOCKED ⚠️
E CLI GraphQL mutations (addReaction/addStar/createIssue) gh unauthenticated BLOCKED ⚠️

Overall: INCONCLUSIVE

⚠️ Part B: All 6 write tools absent from the MCP tool catalog (backend runs with GITHUB_READ_ONLY=1; only 23 read tools exposed). Every write attempt returned unknown tool [-32602]. This confirms the backend/toolset defense-in-depth but cannot independently confirm gateway-level DIFC/guard enforcement, per test methodology.

⚠️ Parts D & E: gh CLI is not authenticated in this environment (gh auth status → "not logged into any GitHub hosts"). REST and GraphQL write probes cannot be executed. The authentication gap means token-scope boundary enforcement cannot be validated in this run.

No writes leaked. Run: §33321440777

🔒 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 (list_issues, list_prs, get_file_contents, list_commits) data returned ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) tools absent from catalog BLOCKED ⚠️
C CLI reads (list_issues, get_file_contents) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment) unauthenticated BLOCKED ⚠️
E CLI GraphQL mutations (addReaction/addStar/createIssue) unauthenticated 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) are absent from the tool catalog. The proxied github CLI exposes exactly 23 read-only tools. This confirms GITHUB_READ_ONLY=1 backend mode — write tools are never registered. However, this does not independently confirm mcpg's own DIFC/guard enforcement layer (gateway-level refusal was not observable since the tools never reached the gateway).

⚠️ Parts D/E: gh CLI has an invalid/unauthenticated token (GH_TOKEN is invalid in this docker-sbx environment). All REST and GraphQL write attempts are INCONCLUSIVE — unauthenticated 401s cannot be distinguished from genuine token-scope blocking.

No write leaked through any surface. The readonly-stress/33321440703 branch, issue, comment, file, PR, star, and reactions were NOT created.

Run: §33321440703

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

@lpcox
lpcox merged commit 1b1457b into main Aug 30, 2026
37 checks passed
@lpcox
lpcox deleted the test-coverage-guard-init-1788021445-6da78314cfc50244 branch August 30, 2026 16:20
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