Guard coverage: classify 21 granular github-mcp-server mutation tools#3860
Guard coverage: classify 21 granular github-mcp-server mutation tools#3860
Conversation
Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/10007b00-6bd5-4623-86ca-e8505618f53c Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates the GitHub guard’s tool classification and DIFC labeling so 21 newly added granular github-mcp-server mutation tools no longer fall through as operation="read" (which bypasses integrity enforcement).
Changes:
- Added 17 granular issue/sub-issue/PR-review tools to
WRITE_OPERATIONSand 4 granular PR update tools toREAD_WRITE_OPERATIONS. - Added
apply_tool_labelsmatch arms to apply repo-scoped secrecy and writer-level integrity for the new tool names. - Added unit tests in
tools.rsto validate the new operation classifications.
Show a summary per file
| File | Description |
|---|---|
guards/github-guard/rust-guard/src/tools.rs |
Extends operation classification allowlists and adds tests for the new tool names. |
guards/github-guard/rust-guard/src/labels/tool_rules.rs |
Applies repo-scoped secrecy + writer integrity for the new granular mutation tools. |
Copilot's findings
Tip
Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comments suppressed due to low confidence (2)
guards/github-guard/rust-guard/src/tools.rs:89
- Same concern for these sub-issue management tools: if the backend returns issue/sub-issue objects, classifying them as
writewill skip the read-side secrecy check and skip response labeling/filtering. If their responses include repo content (likely), they should be inREAD_WRITE_OPERATIONSlikesub_issue_write.
// Sub-issue management tools (alongside sub_issue_write composite)
"add_sub_issue", // POST /repos/.../issues/{number}/sub_issues
"remove_sub_issue", // DELETE/POST — remove sub-issue link
"reprioritize_sub_issue", // PATCH — reorder sub-issues
guards/github-guard/rust-guard/src/tools.rs:98
- These granular PR review tools are decomposed versions of
pull_request_review_write(classified asread-write). Marking them aswriteskips DIFC read/secrecy enforcement and skipsLabelResponse()for the returned review/comment/thread data. Consider classifying them asREAD_WRITE_OPERATIONS(and adjusting tests) unless the MCP server guarantees these responses contain no repo-scoped data.
// PR review tools (alongside pull_request_review_write composite)
"add_pull_request_review_comment", // POST /repos/.../pulls/{number}/comments
"create_pull_request_review", // POST /repos/.../pulls/{number}/reviews
"delete_pending_pull_request_review", // DELETE /repos/.../pulls/{number}/reviews/{id}
"request_pull_request_reviewers", // POST /repos/.../pulls/{number}/requested_reviewers
"resolve_review_thread", // PUT /graphql — resolveReviewThread
"submit_pending_pull_request_review", // POST /repos/.../pulls/{number}/reviews/{id}/events
"unresolve_review_thread", // PUT /graphql — unresolveReviewThread
- Files reviewed: 2/2 changed files
- Comments generated: 2
| // === Granular issue update tools (repo-scoped writes) === | ||
| "update_issue_assignees" | ||
| | "update_issue_body" | ||
| | "update_issue_labels" | ||
| | "update_issue_milestone" | ||
| | "update_issue_state" | ||
| | "update_issue_title" | ||
| | "update_issue_type" => { | ||
| // Granular PATCH tools that modify individual issue fields. | ||
| // S = S(repo); I = writer | ||
| secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx); | ||
| integrity = writer_integrity(repo_id, ctx); | ||
| } | ||
|
|
||
| // === Sub-issue management tools (repo-scoped writes) === | ||
| "add_sub_issue" | "remove_sub_issue" | "reprioritize_sub_issue" => { | ||
| // Sub-issue link creation, removal, and reordering. | ||
| // S = S(repo); I = writer | ||
| secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx); | ||
| integrity = writer_integrity(repo_id, ctx); | ||
| } | ||
|
|
||
| // === Granular PR update tools (repo-scoped read-write) === | ||
| "update_pull_request_body" | ||
| | "update_pull_request_draft_state" | ||
| | "update_pull_request_state" | ||
| | "update_pull_request_title" => { | ||
| // Granular PATCH tools that modify individual PR fields. | ||
| // S = S(repo); I = writer | ||
| secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx); | ||
| integrity = writer_integrity(repo_id, ctx); | ||
| } | ||
|
|
||
| // === PR review tools (repo-scoped writes) === | ||
| "add_pull_request_review_comment" | ||
| | "create_pull_request_review" | ||
| | "delete_pending_pull_request_review" | ||
| | "request_pull_request_reviewers" | ||
| | "resolve_review_thread" | ||
| | "submit_pending_pull_request_review" | ||
| | "unresolve_review_thread" => { | ||
| // PR review creation, commenting, submission, and thread resolution. | ||
| // S = S(repo); I = writer | ||
| secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx); | ||
| integrity = writer_integrity(repo_id, ctx); | ||
| } |
There was a problem hiding this comment.
New tool-specific labeling logic was added here, but there are no corresponding unit tests asserting the expected secrecy/integrity outputs for these tool names. There are existing apply_tool_labels tests for similar repo-scoped write tools (e.g., sub_issue_write), so adding coverage for these new granular tools would help prevent future classification regressions.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
The test expected update_issue_assignees etc. to be write operations, but the tools were never added to any classification list. Following the same pattern as granular PR update tools (which are in READ_WRITE_OPERATIONS alongside update_pull_request), add the granular issue update tools to READ_WRITE_OPERATIONS alongside issue_write. Fix the test to check is_read_write_operation() consistently with the PR update tools test pattern. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Address review feedback: granular sub-issue management tools and PR review tools are decomposed versions of composites already classified as read-write (sub_issue_write, pull_request_review_write). Keeping them as pure write would skip read-side secrecy checks and LabelResponse(), allowing private repo content to bypass enforcement. Changes: - Move add_sub_issue, remove_sub_issue, reprioritize_sub_issue from WRITE_OPERATIONS to READ_WRITE_OPERATIONS - Move 7 PR review tools (add_pull_request_review_comment, etc.) from WRITE_OPERATIONS to READ_WRITE_OPERATIONS - Update tests to check is_read_write_operation() consistently - Add apply_tool_labels tests for all 3 new tool groups (issue update, sub-issue management, PR review) asserting writer integrity Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
21 recently added granular MCP tools in
github-mcp-serverwere falling through tooperation = "read"in the guard, bypassing DIFC integrity enforcement entirely. These tools are decomposed versions of existing composite tools (issue_write,sub_issue_write,update_pull_request,pull_request_review_write) that were already correctly classified.tools.rs— operation classificationAdded to
WRITE_OPERATIONS(17 tools):update_issue_assignees,update_issue_body,update_issue_labels,update_issue_milestone,update_issue_state,update_issue_title,update_issue_typeadd_sub_issue,remove_sub_issue,reprioritize_sub_issueadd_pull_request_review_comment,create_pull_request_review,delete_pending_pull_request_review,request_pull_request_reviewers,resolve_review_thread,submit_pending_pull_request_review,unresolve_review_threadAdded to
READ_WRITE_OPERATIONS(4 tools, consistent withupdate_pull_requestplacement):update_pull_request_body,update_pull_request_draft_state,update_pull_request_state,update_pull_request_titletool_rules.rs— DIFC label applicationAdded four new match arms in
apply_tool_labels, each applying repo-scoped secrecy (S(repo)) and writer-level integrity — following the same pattern as their composite counterparts:Groups: granular issue updates, sub-issue management, granular PR updates, PR review tools.
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:
example.com/tmp/go-build1018101650/b514/launcher.test /tmp/go-build1018101650/b514/launcher.test -test.testlogfile=/tmp/go-build1018101650/b514/testlog.txt -test.paniconexit0 -test.timeout=10m0s 4016�� fg rg/x/net@v0.52.0-ifaceassert x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet fg 4016774/b445/_pkg_.a -trimpath x_amd64/vet -p ntio/asm/cpu/arm--version -lang=go1.25 x_amd64/vet(dns block)invalid-host-that-does-not-exist-12345.com/tmp/go-build1018101650/b496/config.test /tmp/go-build1018101650/b496/config.test -test.testlogfile=/tmp/go-build1018101650/b496/testlog.txt -test.paniconexit0 -test.timeout=10m0s /tmp/go-build1018101650/b387/vet.cfg 1.80.0/internal/go1.25.8 elemetry.io/otel-c=4 x_amd64/vet --gdwarf-5 ity -o x_amd64/vet -o g_.a -trimpath x_amd64/vet -p telabs/wazero/in-atomic -lang=go1.25 x_amd64/vet(dns block)nonexistent.local/tmp/go-build1018101650/b514/launcher.test /tmp/go-build1018101650/b514/launcher.test -test.testlogfile=/tmp/go-build1018101650/b514/testlog.txt -test.paniconexit0 -test.timeout=10m0s 4016�� fg rg/x/net@v0.52.0-ifaceassert x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet fg 4016774/b445/_pkg_.a -trimpath x_amd64/vet -p ntio/asm/cpu/arm--version -lang=go1.25 x_amd64/vet(dns block)slow.example.com/tmp/go-build1018101650/b514/launcher.test /tmp/go-build1018101650/b514/launcher.test -test.testlogfile=/tmp/go-build1018101650/b514/testlog.txt -test.paniconexit0 -test.timeout=10m0s 4016�� fg rg/x/net@v0.52.0-ifaceassert x_amd64/vet --gdwarf-5 --64 -o x_amd64/vet fg 4016774/b445/_pkg_.a -trimpath x_amd64/vet -p ntio/asm/cpu/arm--version -lang=go1.25 x_amd64/vet(dns block)this-host-does-not-exist-12345.com/tmp/go-build1018101650/b523/mcp.test /tmp/go-build1018101650/b523/mcp.test -test.testlogfile=/tmp/go-build1018101650/b523/testlog.txt -test.paniconexit0 -test.timeout=10m0s fg 4016774/b393/_pkg_.a -I x_amd64/vet --gdwarf-5 g/grpc/internal/info -o x_amd64/vet fg 02580/b008/vet.cfg /tmp/go-build1004016774/b288/ x_amd64/vet . --gdwarf2 --64 x_amd64/vet(dns block)If you need me to access, download, or install something from one of these locations, you can either: