Skip to content

feat: surface MCP Gateway guard policy events in gh aw audit#22962

Merged
pelikhan merged 5 commits intomainfrom
copilot/feat-surface-mcp-gateway-events
Mar 25, 2026
Merged

feat: surface MCP Gateway guard policy events in gh aw audit#22962
pelikhan merged 5 commits intomainfrom
copilot/feat-surface-mcp-gateway-events

Conversation

Copy link
Contributor

Copilot AI commented Mar 25, 2026

gh aw audit had no visibility into guard policy enforcement decisions (integrity filtering, repo scoping) from the MCP Gateway. These events appear as JSON-RPC error responses with codes -32001 through -32006 in rpc-messages.jsonl, per the access control specification.

Parsing (gateway_logs.go)

  • Extended rpcError with Data field to capture guard policy error context (reason, repository, details)
  • Added GuardPolicyEvent struct and error code constants (-32001 to -32006) matching the MCP Gateway spec
  • parseRPCMessages() now detects guard policy errors in RESPONSE entries and classifies them by code
  • processGatewayLogEntry() handles GUARD_POLICY_BLOCKED event type from gateway.jsonl
  • Added isGuardPolicyErrorCode() and guardPolicyReasonFromCode() helpers
  • Guard policy metrics aggregated across runs in displayAggregatedGatewayMetrics()

Audit report (audit_report.go, audit_report_render.go)

  • GuardPolicySummary struct with per-category block counts (integrity, repo scope, access denied, blocked user, permissions, private repo) and per-tool/per-server breakdowns
  • Integrated into MCPToolUsageData via buildGuardPolicySummary()
  • renderGuardPolicySummary() renders block reason breakdown, most-blocked-tools table, and event details
  • Server usage table gains a "Guard Blocked" column when events are present

Example log entry parsed

{"direction":"IN","type":"RESPONSE","server_id":"github","payload":{
  "jsonrpc":"2.0","id":1,"error":{
    "code":-32006,
    "message":"Content integrity below minimum threshold",
    "data":{"reason":"integrity_below_minimum","details":"Content integrity 'unapproved' is below minimum 'approved'"}
  }
}}

Tests

7 new unit tests covering error code detection, RPC message parsing with/without data field, gateway.jsonl event handling, summary aggregation, and end-to-end extraction.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/graphql
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GOMOD GOMODCACHE go env on' --ignore-patGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh /usr/bin/gh api graphql -f query=query($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } -f owner=github -f name=gh-aw GOMOD GOMODCACHE go env on' --ignore-patGOINSECURE GO111MODULE x_amd64/asm GOINSECURE GOMOD GOMODCACHE x_amd64/asm (http block)
  • https://api.github.com/orgs/test-owner/actions/secrets
    • Triggering command: /usr/bin/gh gh api /orgs/test-owner/actions/secrets --jq .secrets[].name -json GO111MODULE r: $owner, name:-f GOINSECURE GOMOD GOMODCACHE go env heck '**/*.cjs' '**/*.ts' '**/*.json' --ignore-pGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/actions/ai-inference/git/ref/tags/v1
    • Triggering command: /usr/bin/gh gh api /repos/actions/ai-inference/git/ref/tags/v1 --jq .object.sha user.email test@example.com /usr/bin/git -json GO111MODULE ache/go/1.25.0/x--show-toplevel git rev-�� --git-dir node /usr/bin/gh ithub/workflows **/*.cjs ache/go/1.25.0/x--show-toplevel gh (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v3
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v3 --jq .object.sha /home/REDACTED/work/gh-aw/gh-aw/.github/workflows config ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet remote.origin.urgit GO111MODULE 64/bin/go ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v5
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha k/gh-aw/gh-aw/.github/workflows GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env ithub/workflows GO111MODULE /usr/bin/git GOINSECURE GOMOD ed } } us/3YdcVDbgE0y5Gdx8vjli/alK5YuEv-extld=gcc (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha steps.test.outputs.result /opt/hostedtoolcache/go/1.25.0/x64/pkg/tool/linurev-parse /usr/bin/git /tmp/go-build619git -trimpath me: String!) { --show-toplevel git rev-�� --show-toplevel go /usr/bin/git ithub/workflows GO111MODULE /opt/hostedtoolc--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v5 --jq .object.sha --show-toplevel git /usr/bin/git k/gh-aw/gh-aw/.ggit rev-parse /usr/bin/gh git rev-�� --show-toplevel /usr/bin/gh /usr/bin/git k/gh-aw/gh-aw/.ggit -f /usr/bin/git git (http block)
  • https://api.github.com/repos/actions/checkout/git/ref/tags/v6
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha /tmp/go-build3508351610/b444/testutil.test -importcfg /usr/bin/git -s -w -buildmode=exe git rev-�� --git-dir -extld=gcc /usr/bin/git PdTb/0s0CHCDJ_NAgit GO111MODULE ache/go/1.25.0/x--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha y -buildtags /usr/bin/git -errorsas -ifaceassert -nilfunc git -C /tmp/gh-aw-test-runs/20260325-202110-60580/test-528904228 rev-parse /usr/bin/git @{u} GO111MODULE repository(owne--show-toplevel git (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/checkout/git/ref/tags/v6 --jq .object.sha --show-toplevel 64/pkg/tool/linux_amd64/vet /usr/bin/git k/gh-aw/gh-aw/.ggit GOPROXY /usr/bin/git git rev-�� --show-toplevel git /usr/bin/git ace-editor.md rev-parse .cfg git (http block)
  • https://api.github.com/repos/actions/github-script/git/ref/tags/v8
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha -json GO111MODULE r: $owner, name:-f GOINSECURE GOMOD GOMODCACHE go env heck '**/*.cjs' -f GO111MODULE repository(owne-f GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha setup/js && npm remote.origin.url GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go ache�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/actions/github-script/git/ref/tags/v8 --jq .object.sha heck '**/*.cjs' '**/*.ts' '**/*.json' --ignore-pGOINSECURE GO111MODULE repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } GOINSECURE GOMOD GOMODCACHE go env ck 'scripts/**/*.js' --ignore-path .prettierignoGOINSECURE GO111MODULE r: $owner, name: $name) { hasDiscussionsEnabled } } GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/actions/setup-go/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-go/git/ref/tags/v4 --jq .object.sha k/gh-aw/gh-aw/.github/workflows/auto-triage-issues.md ache/go/1.25.0/x64/pkg/tool/linu-f /usr/bin/git 203188/b412/_pkggit GO111MODULE repository(owne--show-toplevel git chec�� .github/workflows/test.md go /usr/bin/git on GO111MODULE ache/go/1.25.0/x--show-toplevel git (http block)
  • https://api.github.com/repos/actions/setup-node/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/setup-node/git/ref/tags/v4 --jq .object.sha /tmp/TestHashConsistency_GoAndJavaScript3482643270/001/test-fron-errorsas ache/go/1.25.0/x64/pkg/tool/linurev-parse /usr/bin/git -json GO111MODULE ache/go/1.25.0/x--show-toplevel git -C /tmp/gh-aw-test-runs/20260325-202110-60580/test-528904228 status /usr/bin/git .github/workflowgit GO111MODULE ache/go/1.25.0/x--show-toplevel git (http block)
  • https://api.github.com/repos/actions/upload-artifact/git/ref/tags/v4
    • Triggering command: /usr/bin/gh gh api /repos/actions/upload-artifact/git/ref/tags/v4 --jq .object.sha view @sentry/mcp-server@0.29.0 /usr/bin/infocmp -json GO111MODULE $name) { has--show-toplevel infocmp -1 xterm-color go ache/node/24.14.0/x64/bin/node -json GO111MODULE 64/bin/go bash (http block)
  • https://api.github.com/repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b
    • Triggering command: /usr/bin/gh gh api /repos/astral-sh/setup-uv/git/ref/tags/eac588ad8def6316056a12d4907a9d4d84ff7a3b --jq .object.sha b880ad87f35a4a92GOINSECURE GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw --jq .visibility -json GO111MODULE 0/x64/bin/node GOINSECURE GOMOD GOMODCACHE go 8d51�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0 --jq .object.sha 8aaab910b26f1495GOINSECURE GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v0.1.2
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v0.1.2 --jq .object.sha test/concurrent-image:v1.0.0 go /usr/bin/git e=false GO111MODULE repository(owne--show-toplevel git rev-�� --show-toplevel go /usr/bin/git -json GO111MODULE nch,headSha,disp--show-toplevel git (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.0.0 --jq .object.sha 2110-60580/test-528904228 -f /usr/bin/git l owner=github -f git ortc�� /home/REDACTED/work/gh-aw/gh-aw/.github/workflows stmain.go ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet d4970bc8c46a9480git GO111MODULE 64/pkg/tool/linu--show-toplevel ache/go/1.25.0/x64/pkg/tool/linux_amd64/vet (http block)
  • https://api.github.com/repos/github/gh-aw-actions/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw-actions/git/ref/tags/v1.2.3 --jq .object.sha runs/20260325-202110-60580/test-3614265854/.github/workflows rev-parse /usr/bin/gh l GO111MODULE tions/setup/node--show-toplevel /usr/bin/gh api k/gh-aw/gh-aw/.github/workflows -f 0/x64/bin/node -f owner=github -f 8351610/b442/styles.test (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/1/artifacts
    • Triggering command: /usr/bin/gh gh run download 1 --dir test-logs/run-1 GO111MODULE x_amd64/vet GOINSECURE GOMOD GOMODCACHE x_amd64/vet env ithub/workflows GO111MODULE /opt/hostedtoolcache/go/1.25.0/x-nolocalimports GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12345/artifacts
    • Triggering command: /usr/bin/gh gh run download 12345 --dir test-logs/run-12345 GO111MODULE /opt/hostedtoolcache/go/1.25.0/x-lang=go1.25 GOINSECURE GOMOD GOMODCACHE go env ithub/workflows GO111MODULE (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/12346/artifacts
    • Triggering command: /usr/bin/gh gh run download 12346 --dir test-logs/run-12346 GO111MODULE /opt/hostedtoolcache/go/1.25.0/x-nilfunc GOINSECURE GOMOD GOMODCACHE go env ithub/workflows GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE 9d83bdc294c0c826rev-parse GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/2/artifacts
    • Triggering command: /usr/bin/gh gh run download 2 --dir test-logs/run-2 GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env ithub/workflows GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/3/artifacts
    • Triggering command: /usr/bin/gh gh run download 3 --dir test-logs/run-3 GO111MODULE /opt/hostedtoolcache/go/1.25.0/x-nilfunc GOINSECURE GOMOD GOMODCACHE go estl�� ithub/workflows GO111MODULE (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/4/artifacts
    • Triggering command: /usr/bin/gh gh run download 4 --dir test-logs/run-4 GO111MODULE x_amd64/link GOINSECURE GOMOD GOMODCACHE x_amd64/link env ithub/workflows GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE HC/wPHmRHH07drGotDxh6_4/9rUbv3kNVNgnGPLEQds7 (http block)
  • https://api.github.com/repos/github/gh-aw/actions/runs/5/artifacts
    • Triggering command: /usr/bin/gh gh run download 5 --dir test-logs/run-5 GO111MODULE x_amd64/compile GOINSECURE GOMOD GOMODCACHE x_amd64/compile env ithub/workflows GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD ed } } go (http block)
  • https://api.github.com/repos/github/gh-aw/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go ache�� -json GO111MODULE r: $owner, name: $name) { hasDiscussionsEnabled } } GOINSECURE GOMOD GOMODCACHE erignore (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 100 GOMOD GOMODCACHE ache/go/1.25.0/x64/pkg/tool/linu-f env 203188/b412/_pkg_.a GO111MODULE repository(owner: $owner, name:-f GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh run list --json databaseId,number,url,status,conclusion,workflowName,createdAt,startedAt,updatedAt,event,headBranch,headSha,displayTitle --workflow nonexistent-workflow-12345 --limit 6 main -lang=go1.25 go env e=false GO111MODULE me: String!) { repository(owner: $owner, name:-f GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.0.0 --jq .object.sha -json GO111MODULE me: String!) { repository(owne-nilfunc GOINSECURE GOMOD ed } } P5/IKo0RnU6mvci67yPKw6j/HSDucSmurev-parse env ithub/workflows GO111MODULE er: String!, $name: String!) { repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v1.2.3
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v1.2.3 --jq .object.sha -json GO111MODULE repository(owner: $owner, name: $name) { hasDiscussionsEnabled } } GOINSECURE GOMOD ode-gyp-bin/sh go env -json GO111MODULE repository(owne-buildmode=exe GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v2.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE ache/go/1.25.0/x-lang=go1.25 GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE ache/go/1.25.0/x-nilfunc GOINSECURE GOMOD GOMODCACHE go (http block)
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v2.0.0 --jq .object.sha -json GO111MODULE 64/bin/go GOINSECURE GOMOD erignore go env -json GO111MODULE repository(owne-buildmode=exe GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/github/gh-aw/git/ref/tags/v3.0.0
    • Triggering command: /usr/bin/gh gh api /repos/github/gh-aw/git/ref/tags/v3.0.0 --jq .object.sha -json GO111MODULE r: $owner, name: $name) { hasDiscussionsEnabled } } GOINSECURE GOMOD erignore go env -json GO111MODULE ache/go/1.25.0/x-nilfunc GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/githubnext/agentics/git/ref/tags/
    • Triggering command: /usr/bin/gh gh api /repos/githubnext/agentics/git/ref/tags/# --jq .object.sha i-lint >/dev/nulGOINSECURE GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE ache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/nonexistent/action/git/ref/tags/v999.999.999
    • Triggering command: /usr/bin/gh gh api /repos/nonexistent/action/git/ref/tags/v999.999.999 --jq .object.sha ty-test.md GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go env ithout_min-integrity359439230/001 GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go GOINSECURE GOMOD GOMODCACHE go (http block)
  • https://api.github.com/repos/nonexistent/repo/actions/runs/12345
    • Triggering command: /usr/bin/gh gh run view 12345 --repo nonexistent/repo --json status,conclusion GOINSECURE GOMOD GOMODCACHE go env 3614265854/.github/workflows GO111MODULE /opt/hostedtoolcache/go/1.25.0/x64/bin/go l GOMOD ed } } go (http block)
  • https://api.github.com/repos/owner/repo/actions/workflows
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE go ache�� -json GO111MODULE r: $owner, name: $name) { hasDiscussionsEnabled } } GOINSECURE GOMOD GOMODCACHE erignore (http block)
    • Triggering command: /usr/bin/gh gh workflow list --json name,state,path --repo owner/repo 64/bin/go GOINSECURE GOMOD GOMODCACHE go ache�� -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE erignore (http block)
  • https://api.github.com/repos/owner/repo/contents/file.md
    • Triggering command: /tmp/go-build3508351610/b403/cli.test /tmp/go-build3508351610/b403/cli.test -test.testlogfile=/tmp/go-build3508351610/b403/testlog.txt -test.paniconexit0 -test.v=true -test.parallel=4 -test.timeout=10m0s -test.run=^Test -test.short=true GOINSECURE GOMOD GOMODCACHE go env -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE /systemd-executorev-parse (http block)
  • https://api.github.com/repos/test-owner/test-repo/actions/secrets
    • Triggering command: /usr/bin/gh gh api /repos/test-owner/test-repo/actions/secrets --jq .secrets[].name -json GO111MODULE 64/bin/go GOINSECURE GOMOD GOMODCACHE go env heck '**/*.cjs' -f GO111MODULE r: $owner, name:-f GOINSECURE GOMOD GOMODCACHE go (http block)

If you need me to access, download, or install something from one of these locations, you can either:


🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. Learn more about Advanced Security.


Changeset

  • Type: patch
  • Description: Surface MCP Gateway guard policy enforcement events in gh aw audit, including guard-policy error parsing and new report summaries for block reasons, blocked tools, and server-level blocked counts.

Generated by Changeset Generator for issue #22962 ·

Copilot AI and others added 2 commits March 25, 2026 20:25
Add parsing and rendering of guard policy enforcement events (integrity
filtering, repo scoping) from rpc-messages.jsonl and gateway.jsonl.

- Add GuardPolicyEvent struct and guard policy error code constants
  (-32001 to -32006) per MCP Gateway access control specification
- Extend rpcError with Data field to capture guard policy error details
  (reason, repository, details)
- Add guard policy tracking to GatewayMetrics (TotalGuardBlocked,
  GuardPolicyEvents) and GatewayServerMetrics (GuardPolicyBlocked)
- Parse guard policy errors in parseRPCMessages() by detecting JSON-RPC
  error codes -32001 through -32006 in RESPONSE entries
- Handle GUARD_POLICY_BLOCKED event type in processGatewayLogEntry()
  for gateway.jsonl
- Add GuardPolicySummary struct with per-category block counts
  (integrity, repo scope, access denied, blocked user, permissions,
  private repo) and per-tool/per-server breakdowns
- Integrate GuardPolicySummary into MCPToolUsageData and populate via
  buildGuardPolicySummary() in extractMCPToolUsageData()
- Add renderGuardPolicySummary() in audit_report_render.go with block
  reason breakdown, most-blocked-tools table, and event details table
- Add guard policy column to server usage table in
  renderGatewayMetricsTable() and guard policy events table
- Aggregate guard policy metrics in displayAggregatedGatewayMetrics()
- Add 7 unit tests covering guard policy parsing, error code detection,
  summary building, and end-to-end extraction

Closes #22877

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/14aacfd4-6517-43e3-8e4d-b6adab546864

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
- Add comment explaining intentional duplicate events in test data
- Use consistent message truncation length (60 chars) in rendering

Agent-Logs-Url: https://github.com/github/gh-aw/sessions/14aacfd4-6517-43e3-8e4d-b6adab546864

Co-authored-by: Mossaka <5447827+Mossaka@users.noreply.github.com>
Copilot AI changed the title [WIP] Add integrity filtering and guard policy events to gh aw audit feat: surface MCP Gateway guard policy events in gh aw audit Mar 25, 2026
Copilot AI requested a review from Mossaka March 25, 2026 20:28
@Mossaka Mossaka marked this pull request as ready for review March 25, 2026 20:50
Copilot AI review requested due to automatic review settings March 25, 2026 20:50
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds visibility into MCP Gateway guard policy enforcement decisions (JSON-RPC error codes -32001 to -32006 and GUARD_POLICY_BLOCKED log entries) so gh aw audit can report when/why MCP tool calls were blocked.

Changes:

  • Extend gateway log parsing to detect/record guard policy blocks from rpc-messages.jsonl and gateway.jsonl, and aggregate guard-block metrics/events.
  • Add guard policy summary data to MCP tool usage extraction and render a guard policy section in the audit report output.
  • Add unit tests covering guard policy parsing, classification helpers, summary aggregation, and end-to-end extraction.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
pkg/cli/gateway_logs.go Adds guard policy error code detection, event capture, aggregation, and rendering support.
pkg/cli/audit_report.go Adds GuardPolicySummary and wires it into MCPToolUsageData JSON model.
pkg/cli/audit_report_render.go Renders guard policy summary tables/sections in console audit output.
pkg/cli/gateway_logs_test.go Adds tests for guard policy parsing, helpers, and summary extraction.
Comments suppressed due to low confidence (1)

pkg/cli/gateway_logs.go:1222

  • buildGuardPolicySummary categorizes blocks only by evt.ErrorCode. For GUARD_POLICY_BLOCKED entries coming from gateway.jsonl, processGatewayLogEntry currently emits GuardPolicyEvent without setting ErrorCode (zero value), which means these blocks won't be counted in any of the per-reason summary buckets (Integrity/RepoScope/etc) even though TotalBlocked increases. Consider categorizing by evt.Reason when ErrorCode is 0/unknown, or mapping reason->bucket directly so gateway.jsonl-derived events are summarized correctly.
	for _, evt := range metrics.GuardPolicyEvents {
		// Categorize by error code
		switch evt.ErrorCode {
		case guardPolicyErrorCodeIntegrityBelowMin:
			summary.IntegrityBlocked++
		case guardPolicyErrorCodeRepoNotAllowed:
			summary.RepoScopeBlocked++
		case guardPolicyErrorCodeAccessDenied:
			summary.AccessDenied++

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

case guardPolicyErrorCodeAccessDenied:
return "access_denied"
case guardPolicyErrorCodeRepoNotAllowed:
return "repo_not_allowed"
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

guardPolicyReasonFromCode returns "repo_not_allowed" for -32002, but the struct comment/examples (and the gateway error data.reason) use "repository_not_allowed". This inconsistency can lead to mixed reason keys when the optional data.reason field is absent. Consider returning the spec reason string ("repository_not_allowed") here (and updating the corresponding unit test expectations) so the reason values are stable across log formats.

Suggested change
return "repo_not_allowed"
return "repository_not_allowed"

Copilot uses AI. Check for mistakes.
Comment on lines +587 to +595
metrics.GuardPolicyEvents = append(metrics.GuardPolicyEvents, GuardPolicyEvent{
Timestamp: entry.Timestamp,
ServerID: serverKey,
ToolName: entry.ToolName,
Reason: entry.Reason,
Message: entry.Message,
Details: entry.Description,
})
return
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

When handling GUARD_POLICY_BLOCKED in processGatewayLogEntry, the emitted GuardPolicyEvent doesn't set ErrorCode or Repository. If those fields exist (or can be derived from entry.Reason), populating them would allow consistent downstream aggregation/rendering (e.g., buildGuardPolicySummary currently switches on ErrorCode). At minimum, consider setting ErrorCode based on the known Reason strings so bucket counts work for gateway.jsonl logs.

This issue also appears on line 1214 of the same file.

Copilot uses AI. Check for mistakes.
Comment on lines +519 to +522
// Render guard policy summary
if mcpData.GuardPolicySummary != nil && mcpData.GuardPolicySummary.TotalBlocked > 0 {
renderGuardPolicySummary(mcpData.GuardPolicySummary)
}
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

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

The PR description mentions the audit report's server usage table gaining a "Guard Blocked" column when guard events are present, but renderMCPToolUsageTable still renders server headers without this column and MCPServerStats doesn't carry a guard-blocked count. Consider either adding a GuardPolicyBlocked field to MCPServerStats (populated from GatewayServerMetrics.GuardPolicyBlocked) and conditionally rendering the column here, or updating the PR description if the column is only intended for the gateway metrics table.

Copilot uses AI. Check for mistakes.
@Mossaka Mossaka added the smoke label Mar 25, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 25, 2026

❌ Tool validation failed! Agent Container Smoke Test detected missing tools: was cancelled

@github-actions
Copy link
Contributor

github-actions bot commented Mar 25, 2026

💫 TO BE CONTINUED... Smoke Claude was cancelled! Our hero faces unexpected challenges...

@github-actions
Copy link
Contributor

github-actions bot commented Mar 25, 2026

🌑 The shadows whisper... Smoke Codex was cancelled. The oracle requires further meditation...

@github-actions
Copy link
Contributor

📰 BREAKING: Smoke Copilot is now investigating this pull request. Sources say the story is developing...

@github-actions github-actions bot removed the smoke label Mar 25, 2026
@Mossaka Mossaka added the smoke label Mar 25, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 25, 2026

✅ All tools validated successfully! Agent Container Smoke Test confirms agent container is ready.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 25, 2026

✨ The prophecy is fulfilled... Smoke Codex has completed its mystical journey. The stars align. 🌟

@github-actions
Copy link
Contributor

github-actions bot commented Mar 25, 2026

🎬 THE ENDSmoke Claude MISSION: ACCOMPLISHED! The hero saves the day! ✨

@github-actions
Copy link
Contributor

Agent Container Tool Check

Tool Status Version
bash 5.2.21
sh available
git 2.53.0
jq 1.7
yq v4.52.4
curl 8.5.0
gh 2.87.3
node v20.20.1
python3 3.12.3
go 1.24.13
java openjdk 21.0.10
dotnet 10.0.102

Result: 12/12 tools available ✅

Overall Status: PASS

🔧 Tool validation by Agent Container Smoke Test ·

@github-actions
Copy link
Contributor

Smoke Test Results (run §23563669474)

Test
GitHub MCP
MCP Scripts GH CLI
Serena MCP
Playwright
Web Fetch
File Writing + Bash
Discussion Interaction
Build gh-aw
PR Review

Overall: ⚠️ PARTIAL PASS — Serena MCP not available; DIFC filtered PR review replies.

@Mossaka (author) cc @Copilot (assignee)

Note

🔒 Integrity filter blocked 1 item

The following item were blocked because they don't meet the GitHub integrity level.

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

📰 BREAKING: Report filed by Smoke Copilot ·

Copy link
Contributor

@github-actions github-actions bot left a comment

Choose a reason for hiding this comment

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

Smoke test review of PR #22962. The GuardPolicySummary struct addition looks well-structured. Left 2 minor suggestions: consider omitempty on the Events field, and centralizing the MCP error code constants for better discoverability.

Note

🔒 Integrity filter blocked 1 item

The following item were blocked because they don't meet the GitHub integrity level.

  • #22962 pull_request_read: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

📰 BREAKING: Report filed by Smoke Copilot

IntegrityBlocked int `json:"integrity_blocked"` // Blocked by min-integrity (-32006)
RepoScopeBlocked int `json:"repo_scope_blocked"` // Blocked by repos scope (-32002)
AccessDenied int `json:"access_denied"` // General access denied (-32001)
BlockedUserDenied int `json:"blocked_user_denied,omitempty"` // Content from blocked user (-32005)
Copy link
Contributor

Choose a reason for hiding this comment

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

The Events []GuardPolicyEvent field has no omitempty tag unlike other slice fields in this struct. Consider adding omitempty to avoid serializing an empty array when there are no events.


// GuardPolicySummary contains summary statistics for guard policy enforcement.
// Guard policies control which tool calls the MCP Gateway allows based on
// repository scope (repos) and content integrity level (min-integrity).
Copy link
Contributor

Choose a reason for hiding this comment

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

The error codes in comments (-32006, -32002, etc.) are very helpful for debugging. It would be worth documenting these codes in a central location (e.g., a const block or godoc) so they're easier to reference across the codebase.

@github-actions
Copy link
Contributor

📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤

@github-actions
Copy link
Contributor

Commit pushed: 1343164

Generated by Changeset Generator

@github-actions
Copy link
Contributor

Smoke Test: Codex 23563729998

Note

🔒 Integrity filter blocked 1 item

The following item were blocked because they don't meet the GitHub integrity level.

  • #22969 search_pull_requests: has lower integrity than agent requires. The agent cannot read data with integrity below "approved".

To allow these resources, lower min-integrity in your GitHub frontmatter:

tools:
  github:
    min-integrity: approved  # merged | approved | unapproved | none

🔮 The oracle has spoken through Smoke Codex ·

Copy link
Collaborator

@Mossaka Mossaka left a comment

Choose a reason for hiding this comment

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

Reviewed changes and verified smoke tests.

Code review:

  • gateway_logs.go: Guard policy error codes (-32001 to -32006) correctly match the MCP Gateway spec. isGuardPolicyErrorCode() range check, parseRPCMessages() detects guard policy blocks in RPC RESPONSE entries, processGatewayLogEntry() handles GUARD_POLICY_BLOCKED events from gateway.jsonl
  • audit_report.go: GuardPolicySummary struct with per-category counts (integrity, repo scope, access denied, etc.) and per-tool/per-server breakdowns, integrated into MCPToolUsageData
  • audit_report_render.go: Clean rendering with block reason breakdown, most-blocked-tools table, and event details table
  • gateway_logs_test.go: 212 lines of new tests covering error code detection, RPC parsing, summary building
  • No compiler changes, no lock files affected

CI: All 50 checks pass.

Smoke tests:

  • Smoke Copilot: passed
  • Smoke Codex: passed
  • Smoke Claude: safe_outputs job failed due to API rate limiting (not a code bug — agent job itself succeeded)
  • Agent Container Smoke Test: passed

Note: I marked the PR as ready-for-review since the Copilot agent appeared to have finished but left it in draft state.

@pelikhan pelikhan merged commit 1544fae into main Mar 25, 2026
55 checks passed
@pelikhan pelikhan deleted the copilot/feat-surface-mcp-gateway-events branch March 25, 2026 22:08
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.

feat: surface MCP Gateway integrity filtering and guard policy events in gh aw audit

4 participants