Skip to content

Commit 42cff6d

Browse files
authored
feat: add guard tool coverage for 22 missing GitHub MCP server tools (#2280)
## 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. ## Changes ### 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; response refines per-item | | **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) | Private; 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. ### Unit Tests (37 new tests in `labels/mod.rs`) Every new tool now has corresponding unit tests verifying correct secrecy and integrity labels for both `label_resource` and `label_response`, using mock data: - **`apply_tool_labels` (label_resource)**: one test per tool confirming the exact secrecy and integrity labels returned - **`label_response_items`**: `list_gists` (public/private/mixed), `get_gist` (public/private), `list_notifications`, `get_notification_details` (MCP-wrapped) - **`label_response_paths`**: `list_gists` (public/private/mixed), `list_notifications`, `projects_list` (ISSUE/DRAFT_ISSUE/PULL_REQUEST items) ### Proxy router expansion (22 new REST routes + 5 GraphQL patterns) Added explicit routes for Actions, discussions, user, notifications, and check runs to the proxy router. Previously most fell through to the generic `get_file_contents` fallback (wrong security labels) or were blocked entirely. **Valid integrity levels**: `merged` > `approved` > `unapproved` > `none` > `blocked`
2 parents 80e9966 + 85d2f23 commit 42cff6d

9 files changed

Lines changed: 1393 additions & 24 deletions

File tree

guards/github-guard/docs/INTEGRITY_TAG_SPEC.md

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,16 @@ Resource labels are coarse pre-check labels by tool call.
106106
| `get_commit` | start at max(author_association floor, approved); if default-branch reachable => merged | start at author_association floor; if default-branch reachable => merged; otherwise remain floor unless other endorsement applies |
107107
| `list_commits` | if ref is default/no-ref: merged; else max(author_association floor, approved) | if ref is default/no-ref: merged; else author_association floor (response items refine per commit) |
108108
| `get_file_contents` | default/no-ref: merged; otherwise approved (author floor does not usually apply to blob metadata) | default/no-ref: merged; otherwise approved |
109-
| `list_branches`, `list_tags`, `get_tag`, `list_releases`, `get_latest_release`, `get_release_by_tag`, `get_label`, `actions_get`, `actions_list`, `search_code`, `get_repository`, `search_repositories` | approved | approved |
109+
| `list_branches`, `list_tags`, `get_tag`, `list_releases`, `get_latest_release`, `get_release_by_tag`, `get_label`, `list_label`, `actions_get`, `actions_list`, `search_code`, `get_repository`, `search_repositories`, `get_repository_tree`, `list_discussion_categories` | approved | approved |
110+
| `get_job_logs` | approved | approved |
111+
| `list_discussions`, `get_discussion`, `get_discussion_comments` | max(author_association floor, approved) | author_association floor (user content) |
112+
| `list_gists`, `get_gist` | unapproved:user | unapproved:user |
113+
| `list_notifications`, `get_notification_details` | none | none |
110114
| `list_secret_scanning_alerts`, `get_secret_scanning_alert`, `list_code_scanning_alerts`, `get_code_scanning_alert`, `list_dependabot_alerts`, `get_dependabot_alert` | approved | approved |
111-
| `list_issue_types`, `search_users` (GitHub-global metadata) | approved:github | approved:github |
115+
| `list_issue_types`, `search_users`, `search_orgs`, `get_me`, `get_teams`, `get_team_members`, `list_starred_repositories` (GitHub-global/user metadata) | approved:github | approved:github |
116+
| `list_global_security_advisories`, `get_global_security_advisory` (public CVE data) | approved:github | approved:github |
117+
| `list_repository_security_advisories`, `list_org_repository_security_advisories` | approved | approved |
118+
| `projects_list`, `projects_get`, `list_projects`, `get_project`, `list_project_fields`, `list_project_items` | approved:<owner> | approved:<owner> |
112119

113120
Notes:
114121
- Resource labels are intentionally coarse for collection/list/search tools; response labeling performs per-item refinement.
@@ -129,11 +136,19 @@ Response labels are fine-grained per item and are authoritative when available.
129136
| Commit item (`list_commits`, `get_commit`) | max(author_association floor, approved); if default-branch reachable => merged | author_association floor; if default-branch reachable => merged; otherwise stay at floor unless other endorsement evidence applies |
130137
| File content item (`get_file_contents`) | default/no-ref: merged; otherwise approved | default/no-ref: merged; otherwise approved |
131138
| Branch/tag/release metadata item (`list_branches`, `list_tags`, `get_tag`, `list_releases`, `get_latest_release`, `get_release_by_tag`) | merged if tied to default branch, otherwise approved | merged if tied to default branch, otherwise approved |
132-
| Label metadata (`get_label`) | approved | approved |
139+
| Label metadata (`get_label`, `list_label`) | approved | approved |
133140
| GitHub Actions workflow/artifact metadata (`actions_get`, `actions_list`) | approved | approved |
141+
| Job logs (`get_job_logs`) | approved | approved |
134142
| Security alert item | approved | approved |
143+
| Global security advisory (`list_global_security_advisories`, `get_global_security_advisory`) | approved:github | approved:github |
144+
| Repo/org security advisory (`list_repository_security_advisories`, `list_org_repository_security_advisories`) | approved | approved |
145+
| Discussion item (`list_discussions`, `get_discussion`, `get_discussion_comments`) | max(author_association floor, approved) | author_association floor (user content) |
146+
| Discussion category metadata (`list_discussion_categories`) | approved | approved |
135147
| Gist item | unapproved:user | unapproved:user |
136148
| Notification item | currently empty integrity in path-label mode | currently empty integrity in path-label mode |
149+
| Project item (`projects_list`, `projects_get`, `list_project_items`) | approved:<owner> | approved:<owner> |
150+
| User/org metadata (`get_me`, `get_teams`, `get_team_members`, `search_orgs`, `list_starred_repositories`) | approved:github | approved:github |
151+
| Repository tree (`get_repository_tree`) | approved | approved |
137152

138153
Notes:
139154

guards/github-guard/docs/SECRECY_TAG_SPEC.md

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,19 @@ Resource labels are coarse pre-check labels by tool call.
7070

7171
| Tool / Resource Type | Private Repo | Public Repo |
7272
|---|---|---|
73-
| Repo-scoped read tools (`get_issue`, `list_issues`, `get_pull_request`, `list_pull_requests`, `get_commit`, `list_commits`, `get_file_contents`, `list_branches`, `list_tags`, `get_tag`, `list_releases`, `get_latest_release`, `get_release_by_tag`, `get_label`, `actions_get`, `actions_list`, `search_code`, `get_repository`) | `private:<owner>`, `private:<owner>/<repo>` | `[]` |
74-
| Security alert tools (`list_secret_scanning_alerts`, `get_secret_scanning_alert`, `list_code_scanning_alerts`, `get_code_scanning_alert`, `list_dependabot_alerts`, `get_dependabot_alert`) | `private:<owner>`, `private:<owner>/<repo>` (or stricter tool-specific secrecy where configured) | `[]` (or stricter tool-specific secrecy where configured) |
75-
| Cross-repo search tools (`search_issues`, `search_pull_requests`, `search_repositories`, `search_users`) | coarse `[]` (response items refine) | coarse `[]` (response items refine) |
73+
| Repo-scoped read tools (`get_issue`, `list_issues`, `get_pull_request`, `list_pull_requests`, `get_commit`, `list_commits`, `get_file_contents`, `list_branches`, `list_tags`, `get_tag`, `list_releases`, `get_latest_release`, `get_release_by_tag`, `get_label`, `list_label`, `actions_get`, `actions_list`, `search_code`, `get_repository`, `get_repository_tree`, `list_discussions`, `get_discussion`, `get_discussion_comments`, `list_discussion_categories`) | `private:<owner>`, `private:<owner>/<repo>` | `[]` |
74+
| Job logs (`get_job_logs`) | `secret` | `secret` |
75+
| Sensitive file content (`get_file_contents` with sensitive paths) | `secret` | `secret` |
76+
| Secret scanning alerts (`list_secret_scanning_alerts`, `get_secret_scanning_alert`) | `secret` | `secret` |
77+
| Code scanning & Dependabot alerts (`list_code_scanning_alerts`, `get_code_scanning_alert`, `list_dependabot_alerts`, `get_dependabot_alert`) | `private:<owner>`, `private:<owner>/<repo>` | `private:<owner>`, `private:<owner>/<repo>` |
78+
| Repo/org security advisories (`list_repository_security_advisories`, `list_org_repository_security_advisories`) | `private:<owner>`, `private:<owner>/<repo>` | `private:<owner>`, `private:<owner>/<repo>` |
79+
| Artifact downloads (`actions_get` with method `download_workflow_run_artifact`) | `secret` | `secret` |
80+
| User-scoped tools (`get_me`, `get_teams`, `get_team_members`, `list_starred_repositories`) | `private:user` | `private:user` |
81+
| Gist tools (`list_gists`, `get_gist`) | `private:user` (conservative; response refines per-item) | `private:user` (conservative; response refines per-item) |
82+
| Notification tools (`list_notifications`, `get_notification_details`) | `private:user` | `private:user` |
83+
| Cross-repo search tools (`search_issues`, `search_pull_requests`, `search_repositories`, `search_users`, `search_orgs`) | coarse `[]` (response items refine) | coarse `[]` (response items refine) |
84+
| Global security advisories (`list_global_security_advisories`, `get_global_security_advisory`) | `[]` (public CVE data) | `[]` (public CVE data) |
85+
| Project tools (`projects_list`, `projects_get`, `list_projects`, `get_project`, `list_project_fields`, `list_project_items`) | `[]` (response items refine per-item) | `[]` (response items refine per-item) |
7686

7787
Notes:
7888

@@ -94,7 +104,16 @@ Response labels are fine-grained per item and should be treated as authoritative
94104
| File content item (`get_file_contents`) | `private:<owner>`, `private:<owner>/<repo>` | `[]` |
95105
| Branch/tag/release metadata item | `private:<owner>`, `private:<owner>/<repo>` | `[]` |
96106
| GitHub Actions workflow/artifact metadata | `private:<owner>`, `private:<owner>/<repo>` | `[]` |
107+
| Job logs (`get_job_logs`) | `secret` | `secret` |
97108
| Security alert item | `private:<owner>`, `private:<owner>/<repo>` (or stricter tool-specific secrecy where configured) | `[]` (or stricter tool-specific secrecy where configured) |
109+
| Global security advisory | `[]` (public CVE data) | `[]` (public CVE data) |
110+
| Repo/org security advisory | `private:<owner>`, `private:<owner>/<repo>` | `private:<owner>`, `private:<owner>/<repo>` |
111+
| Discussion item (`list_discussions`, `get_discussion`, `get_discussion_comments`) | `private:<owner>`, `private:<owner>/<repo>` | `[]` |
112+
| Discussion category metadata (`list_discussion_categories`) | `private:<owner>`, `private:<owner>/<repo>` | `[]` |
113+
| Gist item (`list_gists`, `get_gist`) | `private:user` (secret gists) / `[]` (public gists) | `private:user` (secret gists) / `[]` (public gists) |
114+
| Notification item (`list_notifications`, `get_notification_details`) | `private:user` | `private:user` |
115+
| Project item (`projects_list`, `list_project_items`) | per-item from referenced repo | per-item from referenced repo |
116+
| User/org metadata (`get_me`, `get_teams`, `get_team_members`, `list_starred_repositories`, `search_orgs`) | `private:user` (user-scoped) / `[]` (org search) | `private:user` / `[]` |
98117

99118
---
100119

0 commit comments

Comments
 (0)