Skip to content

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

Description

@github-actions

Summary

The GitHub guard currently models a broader write surface than the official github-mcp-server README exposes, but that coverage is now stale in 39 places relative to the upstream MCP tool list. These entries still appear in guards/github-guard/rust-guard/src/tools.rs, yet they no longer appear in the upstream MCP server's published tool catalog. That drift makes the guard harder to audit and can hide real gaps behind synthetic or obsolete entries.

In addition, the stale entries largely correspond to GitHub CLI-only mutations. Those operations are still reachable via gh, but they are not represented by current upstream MCP tools, so they should be tracked explicitly as synthetic CLI coverage rather than blended into the MCP tool inventory.

  • MCP tools scanned: 89
  • CLI write commands scanned: 39
  • Guard-covered write tools (tools.rs): 141
  • Tools with explicit DIFC rules (tool_rules.rs): 257 string-matched names
  • New gaps found this run: 39

Stale Guard Entries (tools.rs)

These entries are present in WRITE_OPERATIONS / READ_WRITE_OPERATIONS but are not present in the upstream github-mcp-server README tool list:

Guard Entry Current Role Likely Source Recommended Action
add_project_item deprecated alias legacy/synthetic Projects mapping Remove from canonical write lists or move to an explicit synthetic/alias section with comments and tests
archive_repository blocked write CLI-only repo command Keep only if synthetic CLI coverage is intentional; otherwise remove from MCP-derived inventory
cancel_workflow_run synthetic write gh run cancel Move to dedicated CLI synthetic coverage set
copy_project synthetic write gh project copy Move to dedicated CLI synthetic coverage set
create_agent_task blocked write gh agent-task create Keep only in a clearly named CLI-only/blocked section
create_project synthetic write gh project create Move to dedicated CLI synthetic coverage set
delete_actions_cache synthetic write gh cache delete Move to dedicated CLI synthetic coverage set
delete_gist synthetic write gh gist delete Move to dedicated CLI synthetic coverage set
delete_project synthetic write gh project delete Move to dedicated CLI synthetic coverage set
delete_project_item deprecated alias legacy/synthetic Projects mapping Remove alias or isolate under compatibility handling
delete_secret synthetic write gh secret delete Move to dedicated CLI synthetic coverage set
delete_variable synthetic write gh variable delete Move to dedicated CLI synthetic coverage set
delete_workflow_run_logs deprecated alias legacy workflow mapping Remove if no longer used by guard callers
disable_workflow synthetic write gh workflow disable Move to dedicated CLI synthetic coverage set
enable_toolset synthetic capability write guard/runtime-specific Keep outside upstream MCP comparison path
enable_workflow synthetic write gh workflow enable Move to dedicated CLI synthetic coverage set
force_cancel_workflow_run synthetic write gh run cancel --force Move to dedicated CLI synthetic coverage set
link_project synthetic write gh project link Move to dedicated CLI synthetic coverage set
mark_pull_request_as_draft synthetic write gh pr ready --undo Move to dedicated CLI synthetic coverage set
mark_pull_request_as_ready_for_review synthetic write gh pr ready Move to dedicated CLI synthetic coverage set
pin_issue synthetic write gh issue pin Move to dedicated CLI synthetic coverage set
rebuild_codespace synthetic write gh codespace rebuild Move to dedicated CLI synthetic coverage set
rename_repository blocked write gh repo rename Keep only in explicit CLI-only blocked coverage
rerun_failed_jobs synthetic write gh run rerun --failed Move to dedicated CLI synthetic coverage set
rerun_workflow_job synthetic write gh run rerun --job Move to dedicated CLI synthetic coverage set
rerun_workflow_run synthetic write gh run rerun Move to dedicated CLI synthetic coverage set
run_workflow deprecated alias legacy workflow mapping Remove alias or isolate under compatibility handling
set_secret synthetic write gh secret set Move to dedicated CLI synthetic coverage set
set_variable synthetic write gh variable set Move to dedicated CLI synthetic coverage set
sync_fork synthetic write gh repo sync Move to dedicated CLI synthetic coverage set
transfer_issue synthetic write gh issue transfer Move to dedicated CLI synthetic coverage set
transfer_repository blocked write repo ownership transfer Keep only in explicit CLI-only blocked coverage
unarchive_repository blocked write gh repo unarchive Keep only in explicit CLI-only blocked coverage
unlink_project synthetic write gh project unlink Move to dedicated CLI synthetic coverage set
unpin_issue synthetic write gh issue unpin Move to dedicated CLI synthetic coverage set
update_codespace_port_visibility synthetic write gh codespace ports visibility Move to dedicated CLI synthetic coverage set
update_project synthetic write gh project close/edit/reopen Move to dedicated CLI synthetic coverage set
update_project_draft_issue synthetic write gh project item-edit --title/--body Move to dedicated CLI synthetic coverage set
update_project_item deprecated alias legacy/synthetic Projects mapping Remove alias or isolate under compatibility handling

Why this matters

Today the guard conflates three different concepts in the same classification lists:

  1. Actual upstream MCP tools from github-mcp-server
  2. Synthetic CLI-only operations that have no upstream MCP counterpart
  3. Deprecated aliases / compatibility names

That makes automated coverage checks noisy and obscures whether a missing entry is a real upstream regression or just a local synthetic mapping.


Suggested remediation

1. Split the inventories in tools.rs

Create separate constants for upstream MCP tools vs. synthetic CLI-only coverage vs. deprecated aliases. For example:

pub const WRITE_OPERATIONS: &[&str] = &[
    // upstream github-mcp-server write tools only
    "actions_run_trigger",
    "add_issue_comment",
    "create_pull_request",
    // ...
];

pub const CLI_WRITE_OPERATIONS: &[&str] = &[
    // gh-only synthetic coverage
    "cancel_workflow_run",
    "copy_project",
    "delete_actions_cache",
    "set_secret",
    "transfer_issue",
    // ...
];

pub const DEPRECATED_WRITE_ALIASES: &[&str] = &[
    "add_project_item",
    "delete_project_item",
    "delete_workflow_run_logs",
    "run_workflow",
    "update_project_item",
];

Then make is_write_operation() / is_read_write_operation() consult all relevant sets deliberately, instead of forcing every synthetic entry into the MCP-derived canonical lists.

2. Adjust the coverage checker contract

Treat only upstream MCP entries as candidates for MCP drift. Treat CLI_WRITE_OPERATIONS as a separate audited set compared against cli/cli write commands.

3. Keep DIFC rules, but point them at the split sets

The explicit match arms in tool_rules.rs for these operations are still useful. The issue is not that the labels are wrong; it is that the tool inventory mixes unrelated sources. Preserve the existing labeling rules, but document whether each rule is for:

  • upstream MCP tools,
  • synthetic CLI-only operations, or
  • deprecated compatibility aliases.

4. Add an invariant test

Add a test that asserts every WRITE_OPERATIONS / READ_WRITE_OPERATIONS entry belongs to exactly one source bucket:

#[test]
fn write_entries_belong_to_a_single_source_bucket() {
    // every write classification should be upstream MCP, synthetic CLI, or deprecated alias
    // but not mixed implicitly in one canonical list
}

CLI mapping context

The stale entries above are not arbitrary; they map to real CLI mutations such as:

CLI Command Guard Entry Notes
gh cache delete delete_actions_cache CLI-only, no current upstream MCP tool
gh workflow enable enable_workflow CLI-only, no current upstream MCP tool
gh workflow disable disable_workflow CLI-only, no current upstream MCP tool
gh issue transfer transfer_issue CLI-only, no current upstream MCP tool
gh project copy copy_project CLI-only GraphQL mutation
gh project link / unlink link_project / unlink_project CLI-only GraphQL mutation
gh codespace rebuild rebuild_codespace CLI-only session mutation
gh secret set / delete set_secret / delete_secret CLI-only secret mutation

These should remain guardable, but they should not masquerade as current upstream MCP tools.


References

Generated by GitHub Guard Coverage Checker (MCP + CLI) · gpt54 · 86.1 AIC · ⊞ 34.9K ·

  • expires on Sep 1, 2026, 2:34 AM UTC

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions