Skip to content

Cover notification and star mutations in GitHub guard - #12105

Merged
lpcox merged 5 commits into
mainfrom
copilot/guard-coverage-fix
Aug 30, 2026
Merged

Cover notification and star mutations in GitHub guard#12105
lpcox merged 5 commits into
mainfrom
copilot/guard-coverage-fix

Conversation

Copilot AI commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

The GitHub guard was missing or misclassifying several mutating upstream MCP tools, leaving notification and star operations without the intended write/read-write inventory coverage and DIFC labels.

  • Tool classification
    • Classifies notification dismiss/read-all and star/unstar as write operations.
    • Classifies notification subscription management as read-write operations.
pub const WRITE_OPERATIONS: &[&str] = &[
    "dismiss_notification",
    "mark_all_notifications_read",
    "star_repository",
    "unstar_repository",
];

pub const READ_WRITE_OPERATIONS: &[&str] = &[
    "manage_notification_subscription",
    "manage_repository_notification_subscription",
];
  • DIFC labeling

    • Labels notification management and star/unstar as authenticated user state:
      • secrecy: private:user
      • integrity: approved:user
    • Keeps account-scoped baseline inference ahead of generic repo fallback so repo arguments do not accidentally relabel user-scoped mutations.
  • Regression coverage

    • Adds focused tests for the six upstream operations’ inventory buckets.
    • Adds baseline-scope tests for notification/star tools and preserves existing account-scoped behavior for codespace and secret/variable operations.

Copilot AI and others added 3 commits August 29, 2026 16:30
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copilot AI changed the title [WIP] Add coverage for missing operations in guard Cover notification and star mutations in GitHub guard Aug 29, 2026
Copilot AI requested a review from lpcox August 29, 2026 16:42
@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
@github-actions

This comment has been minimized.

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

Plain-text mutation responses bypass the new secrecy rules and remain publicly labeled.

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

Pull request overview

Updates GitHub guard coverage for notification and star mutations.

Changes:

  • Corrects write/read-write classifications.
  • Applies user-scoped DIFC labels.
  • Adds classification and baseline regression tests.
File summaries
File Description
src/tools.rs Updates operation inventories and tests.
src/lib.rs Prioritizes account-scoped baseline inference.
src/labels/tool_rules.rs Adds private user labels.
src/labels/mod.rs Updates label tests.
Review details

Suppressed comments (1)

guards/github-guard/rust-guard/src/labels/tool_rules.rs:890

  • The star/unstar success payloads still bypass this new secrecy rule. Both upstream tools return a plain NewToolResultText(...); after extraction, apply_singleton_fallback_if_needed classifies that wrapper as server metadata and emits secrecy: [] without calling apply_tool_labels (lib.rs:361-390). As a result, response labeling remains public even though resource labeling is now private:user. Apply tool-specific labels in the plaintext fallback and cover the actual wrapped success shape.
            secrecy = private_user_label();
            baseline_scope = Cow::Borrowed(scope_names::USER);
            integrity = writer_integrity(scope_names::USER, ctx);
  • Files reviewed: 4/4 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 on lines +615 to +617
secrecy = private_user_label();
baseline_scope = Cow::Borrowed(scope_names::USER);
integrity = writer_integrity(scope_names::USER, ctx);
@github-actions

This comment has been minimized.

@lpcox

lpcox commented Aug 29, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

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

Copilot AI commented Aug 29, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Addressed in 6753034. Plain-text notification mutation responses now retain tool-specific private:user secrecy, with regression coverage for the affected operations.

@github-actions

Copy link
Copy Markdown
Contributor

🔒 mcpg Read-Only Stress — default AWF

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

Part Surface Op Result Expected Status
A MCP reads (issues/PRs/file/commits) data returned (all 4) ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) all 7 tools absent from catalog BLOCKED ⚠️
C CLI reads (issues/file via github bridge) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment/file) gh unauthenticated (no GH_TOKEN) BLOCKED ⚠️
E CLI GraphQL mutations (addReaction/addStar/createIssue) gh unauthenticated (no GH_TOKEN) BLOCKED ⚠️

Overall: INCONCLUSIVE

⚠️ Part B gap: All 7 write tools (add_issue_comment, star_repository, issue_write, create_branch, create_or_update_file, create_pull_request) were absent from the MCP tool catalog — the backend registered only 23 read-only tools because GITHUB_READ_ONLY=1 is unconditionally set by gh-aw's tools.github: wrapper. Refusals only confirm backend/toolset config, not gateway-level DIFC enforcement. This is expected and documented behavior.

⚠️ Parts D/E gap: gh CLI is unauthenticated in this sandbox (no GH_TOKEN). All write attempts returned "set GH_TOKEN env variable" — cannot distinguish token-scope blocking from missing auth. Token-scope boundary not validated in this run.

No writes leaked. No FAIL conditions observed.

🔒 mcpg read-only stress (default AWF runtime) by Read-Only Stress: default 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) data returned ALLOWED
B MCP writes (reaction/star/issue/comment/branch/file/PR) tool absent from catalog BLOCKED ⚠️
C CLI reads (list_issues, get_file_contents) data returned ALLOWED
D CLI REST writes (reaction/star/issue/comment/file) unauthenticated BLOCKED ⚠️
E CLI GraphQL mutations (addReaction/addStar/createIssue) unauthenticated BLOCKED ⚠️

Overall: INCONCLUSIVE

⚠️ Part B gap: All 7 write tool targets (add_issue_comment, star_repository, issue_write, create_branch, create_or_update_file, create_pull_request) were absent from the gateway-exposed tool catalog (23 read-only tools only). The backend runs with GITHUB_READ_ONLY=1, which removes write tools before they reach mcpg. This confirms the gh-aw framework's own defense-in-depth guarantee but does not independently confirm mcpg's DIFC/guard enforcement layer for this runtime. Result: INCONCLUSIVE (not FAIL).

⚠️ Parts D & E gap: gh CLI is unauthenticated in this docker-sbx environment (GH_TOKEN is invalid — 401 Bad credentials). REST and GraphQL write attempts cannot confirm the token-scope boundary. Result: INCONCLUSIVE (not FAIL).

No write leaked. No FAIL conditions observed. INCONCLUSIVE due to structural test-surface gaps (read-only backend + unauthenticated gh), identical to default/gvisor runtime behavior.

References: §33269560599

🔒 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 — 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 list_issues 3 issues returned ALLOWED
A MCP list_pull_requests 3 PRs returned ALLOWED
A MCP get_file_contents (README.md) file downloaded ALLOWED
A MCP list_commits 3 commits returned ALLOWED
B MCP add_issue_comment (reaction) ABSENT from catalog BLOCKED ⚠️
B MCP star_repository ABSENT from catalog BLOCKED ⚠️
B MCP issue_write ABSENT from catalog BLOCKED ⚠️
B MCP add_issue_comment (body) ABSENT from catalog BLOCKED ⚠️
B MCP create_branch ABSENT from catalog BLOCKED ⚠️
B MCP create_or_update_file ABSENT from catalog BLOCKED ⚠️
B MCP create_pull_request ABSENT from catalog BLOCKED ⚠️
C CLI github list_issues 3 issues returned ALLOWED
C CLI github get_file_contents README.md downloaded 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

⚠️ Notes:

  • Part B: All 7 write tools were ABSENT from the MCP catalog (backend launched with GITHUB_READ_ONLY=1). No write tool was listed AND refused — this confirms the gh-aw framework's defense-in-depth but cannot independently confirm gateway-level DIFC enforcement for this surface. See architectural note in test plan.
  • Parts D/E: gh CLI is not authenticated in this environment (gh auth status shows no logged-in hosts). All CLI write attempts would return unauthenticated 401s — not evidence of gateway enforcement. INCONCLUSIVE per test methodology.
  • No writes succeeded — zero leaks observed across all surfaces.
  • gVisor note: The /tmp/gh-aw/agent/ directory was not writable under gVisor's overlay filesystem (mount appears read-only despite correct POSIX permissions). Result file written to /tmp/gh-aw/readonly-stress-result-33269560607.txt as fallback.

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

@lpcox
lpcox merged commit bc4e02f into main Aug 30, 2026
38 checks passed
@lpcox
lpcox deleted the copilot/guard-coverage-fix branch August 30, 2026 16:11
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.

[guard-coverage] Guard coverage gap: 6 operations from github-mcp-server / GitHub CLI not fully covered

3 participants