Skip to content

Commit 68537a8

Browse files
authored
feat: guard tool coverage for GitHub MCP server + proxy router expansion (#2291)
## Problem Cross-referencing all tool names from `github/github-mcp-server` source against the guard's `tool_rules.rs` revealed 22 read tools falling through to the default `_ =>` case, which inherits empty labels. This means these tools had no integrity or secrecy labeling, causing them to either be filtered at any `min-integrity` threshold or leak private data without secrecy tags. Additionally, the proxy router had gaps where Actions, discussions, user, and notification endpoints either fell through to a generic `get_file_contents` fallback (wrong security labels) or were blocked entirely. ## Changes ### Guard: New tool coverage in `tool_rules.rs` (22 read tools) | Category | Tools | Secrecy | Integrity | Rationale | |----------|-------|---------|-----------|-----------| | **Actions** | `get_job_logs` | `secret` | approved | Logs may contain leaked env vars/tokens | | **Context** | `get_me` | `private:user` | project:github | User PII (email, profile) | | **Context** | `get_teams`, `get_team_members` | `private:user` | project:github | Org structure is sensitive | | **Discussions** | `list_discussions`, `get_discussion` | repo visibility | approved | User content, similar to issues | | **Discussions** | `get_discussion_comments` | repo visibility | approved | User content, similar to issue comments | | **Discussions** | `list_discussion_categories` | repo visibility | approved | Maintainer-managed metadata | | **Gists** | `list_gists`, `get_gist` | `private:user` | unapproved | User content, no repo-level trust signal | | **Git** | `get_repository_tree` | repo visibility | approved | Repo metadata | | **Labels** | `list_label` | repo visibility | approved | Maintainer-managed metadata | | **Notifications** | `list_notifications`, `get_notification_details` | `private:user` | none (empty) | References external content of unknown trust | | **Projects** | `projects_list`, `projects_get` | `[]` | approved:owner | New canonical project tool names | | **Repos** | `list_starred_repositories` | `private:user` | project:github | Reveals user preferences/interests | | **Search** | `search_orgs` | `[]` | project:github | Public GitHub-controlled metadata | | **Security** | `list_global_security_advisories`, `get_global_security_advisory` | `[]` | project:github | Published GHSA CVE data | | **Security** | `list_repository_security_advisories`, `list_org_repository_security_advisories` | `private:repo` | approved | May contain embargoed vulnerability info | Also updated `tools.rs`: added `actions_run_trigger`, `projects_write`, `add_reply_to_pull_request_comment` to write operations. ### Guard: Unit tests (37 new tests) Every new tool has corresponding tests for `label_resource` and `label_response`. ### Guard: Compiler warning fix Gated `has_approval_label` with `#[cfg(test)]` (only used in tests). ### Proxy: 22 new REST routes + 5 GraphQL patterns - **Actions**: get workflow/run/job, workflow-specific runs, attempt jobs/logs, artifacts, caches, secrets, variables, environment config - **Discussions**: list, single, comments (REST + GraphQL) - **User**: `/user`, `/user/keys|ssh_signing_keys|gpg_keys` (REST), `viewer {}` (GraphQL) - **Notifications**: `/notifications` - **Check runs**: `/commits/{sha}/check-runs|check-suites` - **Org-scoped**: `/orgs/{org}/actions/secrets|variables` - **Organization**: `organization()` GraphQL **Valid integrity levels**: `merged` > `approved` > `unapproved` > `none` > `blocked`
2 parents 2c9876b + 970f020 commit 68537a8

2 files changed

Lines changed: 4 additions & 1 deletion

File tree

guards/github-guard/rust-guard/src/labels/helpers.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ fn extract_github_label_names<'a>(item: &'a Value) -> Vec<&'a str> {
212212

213213
/// Check whether a content item carries at least one label from the configured
214214
/// `approval-labels` list (case-insensitive comparison).
215+
#[cfg(test)]
215216
pub fn has_approval_label(item: &Value, ctx: &PolicyContext) -> bool {
216217
first_matching_approval_label(item, ctx).is_some()
217218
}

guards/github-guard/rust-guard/src/labels/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,14 @@ pub use constants::MEDIUM_BUFFER_SIZE;
4444
pub use helpers::{
4545
blocked_integrity, commit_integrity, ensure_integrity_baseline, extract_items_array,
4646
extract_number_as_string, extract_repo_from_item, extract_repo_info,
47-
extract_repo_info_from_search_query, get_bool_or, get_nested_str, get_str_or, has_approval_label,
47+
extract_repo_info_from_search_query, get_bool_or, get_nested_str, get_str_or,
4848
is_blocked_user, is_bot, issue_integrity, limit_items_with_log, make_item_path, merged_integrity,
4949
none_integrity, pr_integrity, private_scope_label, private_user_label, project_github_label,
5050
reader_integrity, secret_label, writer_integrity, MinIntegrity, PolicyContext, PolicyScopeEntry,
5151
ScopeKind,
5252
};
53+
#[cfg(test)]
54+
pub use helpers::has_approval_label;
5355

5456
// Re-export response labeling functions (wrappers that pass PolicyContext)
5557
pub fn apply_tool_labels(

0 commit comments

Comments
 (0)