Skip to content

Commit f0fef19

Browse files
authored
rust-guard: consolidate github-baseline match arms + add Display for ScopeKind (#2640)
Seven match arms in `apply_tool_labels` repeated identical `baseline_scope = "github"` and `integrity = project_github_label(ctx)` assignments, differing only in `secrecy`. `ScopeKind` had no `Display` impl, forcing a private 5-arm match in `normalized_scope_kind` just to stringify variants. ### `tool_rules.rs` — merge 7 arms into 2 Group by secrecy value; eliminate ~40 lines of near-identical code: ```rust // Before: 7 separate arms, each repeating baseline_scope + integrity // After: "get_me" | "get_teams" | "get_team_members" | "list_starred_repositories" | "get_copilot_space" | "list_copilot_spaces" => { secrecy = private_user_label(); baseline_scope = "github".to_string(); integrity = project_github_label(ctx); } "search_orgs" | "list_global_security_advisories" | "get_global_security_advisory" | "github_support_docs_search" => { secrecy = vec![]; baseline_scope = "github".to_string(); integrity = project_github_label(ctx); } ``` ### `helpers.rs` — add `Display` for `ScopeKind` Moves variant→string conversion onto the type where it belongs, making it available to any future caller via `.to_string()` or `{}` formatting. ### `lib.rs` — simplify `normalized_scope_kind` Replaces the 5-arm match with a single `scopes[0].scope_kind.to_string()` call. > [!WARNING] > > <details> > <summary>Firewall rules blocked me from connecting to one or more addresses (expand for details)</summary> > > #### I tried to connect to the following addresses, but was blocked by firewall rules: > > - `example.com` > - Triggering command: `/tmp/go-build2380398191/b334/launcher.test /tmp/go-build2380398191/b334/launcher.test -test.testlogfile=/tmp/go-build2380398191/b334/testlog.txt -test.paniconexit0 -test.timeout=10m0s ache�� g_.a rg x_amd64/vet` (dns block) > - `invalid-host-that-does-not-exist-12345.com` > - Triggering command: `/tmp/go-build2380398191/b319/config.test /tmp/go-build2380398191/b319/config.test -test.testlogfile=/tmp/go-build2380398191/b319/testlog.txt -test.paniconexit0 -test.timeout=10m0s conf�� ternal/engine/interpreter/compiler.go ternal/engine/interpreter/format.go x_amd64/compile` (dns block) > - `nonexistent.local` > - Triggering command: `/tmp/go-build2380398191/b334/launcher.test /tmp/go-build2380398191/b334/launcher.test -test.testlogfile=/tmp/go-build2380398191/b334/testlog.txt -test.paniconexit0 -test.timeout=10m0s ache�� g_.a rg x_amd64/vet` (dns block) > - `slow.example.com` > - Triggering command: `/tmp/go-build2380398191/b334/launcher.test /tmp/go-build2380398191/b334/launcher.test -test.testlogfile=/tmp/go-build2380398191/b334/testlog.txt -test.paniconexit0 -test.timeout=10m0s ache�� g_.a rg x_amd64/vet` (dns block) > - `this-host-does-not-exist-12345.com` > - Triggering command: `/tmp/go-build2380398191/b343/mcp.test /tmp/go-build2380398191/b343/mcp.test -test.testlogfile=/tmp/go-build2380398191/b343/testlog.txt -test.paniconexit0 -test.timeout=10m0s -o /proxy/graphql.go /proxy/graphql_rewrite.go x_amd64/vet -p syscall -lang=go1.25 x_amd64/vet -I g_.a 5678121/b151/ x_amd64/vet --gdwarf-5 ernal/middleware-qE` (dns block) > > If you need me to access, download, or install something from one of these locations, you can either: > > - Configure [Actions setup steps](https://gh.io/copilot/actions-setup-steps) to set up my environment, which run before the firewall is enabled > - Add the appropriate URLs or hosts to the custom allowlist in this repository's [Copilot coding agent settings](https://github.com/github/gh-aw-mcpg/settings/copilot/coding_agent) (admins only) > > </details> <!-- START COPILOT CODING AGENT TIPS --> --- 🔒 GitHub Advanced Security automatically protects Copilot coding agent pull requests. You can protect all pull requests by enabling Advanced Security for your repositories. [Learn more about Advanced Security.](https://gh.io/cca-advanced-security)
2 parents a81b5bd + 212e2cf commit f0fef19

3 files changed

Lines changed: 31 additions & 63 deletions

File tree

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,19 @@ pub enum ScopeKind {
5454
RepoPrefix,
5555
}
5656

57+
impl std::fmt::Display for ScopeKind {
58+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
59+
let s = match self {
60+
ScopeKind::All => "All",
61+
ScopeKind::Public => "Public",
62+
ScopeKind::Owner => "Owner",
63+
ScopeKind::Repo => "Repo",
64+
ScopeKind::RepoPrefix => "RepoPrefix",
65+
};
66+
f.write_str(s)
67+
}
68+
}
69+
5770
#[derive(Debug, Clone, PartialEq, Eq)]
5871
pub struct PolicyScopeEntry {
5972
pub scope_kind: ScopeKind,

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

Lines changed: 17 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -474,56 +474,37 @@ pub fn apply_tool_labels(
474474
integrity = vec![];
475475
}
476476

477-
// === Context: User & Org Identity ===
478-
"get_me" => {
479-
// Current user profile — private to the authenticated user.
480-
// May contain private email, name, and other PII.
477+
// === Private GitHub-controlled metadata (user-associated): PII/org-structure sensitive ===
478+
"get_me"
479+
| "get_teams"
480+
| "get_team_members"
481+
| "list_starred_repositories"
482+
| "get_copilot_space"
483+
| "list_copilot_spaces" => {
484+
// User profile, org team membership, starred repos, and Copilot Spaces are all
485+
// GitHub-controlled metadata that may contain PII or reveal internal org structure.
481486
// S = private:user
482487
// I = project:github (GitHub-controlled metadata)
483488
secrecy = private_user_label();
484489
baseline_scope = "github".to_string();
485490
integrity = project_github_label(ctx);
486491
}
487492

488-
"get_teams" | "get_team_members" => {
489-
// Org team membership — may reveal internal org structure.
490-
// S = private:user (org membership is sensitive)
491-
// I = project:github (GitHub-controlled metadata)
492-
secrecy = private_user_label();
493-
baseline_scope = "github".to_string();
494-
integrity = project_github_label(ctx);
495-
}
496-
497-
// === Starred Repositories ===
498-
"list_starred_repositories" => {
499-
// User's starred repos — reveals user preferences/interests.
500-
// S = private:user (personal data)
501-
// I = project:github (GitHub-controlled metadata)
502-
secrecy = private_user_label();
503-
baseline_scope = "github".to_string();
504-
integrity = project_github_label(ctx);
505-
}
506-
507-
// === Organization Search ===
508-
"search_orgs" => {
509-
// Public organization profiles.
493+
// === Public GitHub-controlled metadata: org profiles, advisories, docs ===
494+
"search_orgs"
495+
| "list_global_security_advisories"
496+
| "get_global_security_advisory"
497+
| "github_support_docs_search" => {
498+
// Public organization profiles, global CVE advisories, and GitHub docs contain no
499+
// private data but are curated/controlled by GitHub.
510500
// S = public (empty)
511501
// I = project:github (GitHub-controlled metadata)
512502
secrecy = vec![];
513503
baseline_scope = "github".to_string();
514504
integrity = project_github_label(ctx);
515505
}
516506

517-
// === Security Advisories ===
518-
"list_global_security_advisories" | "get_global_security_advisory" => {
519-
// Global security advisories are public CVE data from GHSA.
520-
// S = public (empty) — these are published advisories
521-
// I = project:github — curated by GitHub security team
522-
secrecy = vec![];
523-
baseline_scope = "github".to_string();
524-
integrity = project_github_label(ctx);
525-
}
526-
507+
// === Security Advisories (repository/org-scoped) ===
527508
"list_repository_security_advisories" | "list_org_repository_security_advisories" => {
528509
// Repository/org security advisories may include draft advisories
529510
// with non-public vulnerability details.
@@ -533,26 +514,6 @@ pub fn apply_tool_labels(
533514
integrity = writer_integrity(repo_id, ctx);
534515
}
535516

536-
// === Copilot Spaces (org/user-scoped) ===
537-
"get_copilot_space" | "list_copilot_spaces" => {
538-
// Copilot Spaces are org-scoped; may contain private configuration or policies.
539-
// S = private:user (conservative — spaces may reference private data)
540-
// I = project:github (GitHub-controlled metadata)
541-
secrecy = private_user_label();
542-
baseline_scope = "github".to_string();
543-
integrity = project_github_label(ctx);
544-
}
545-
546-
// === GitHub Support Docs Search (public) ===
547-
"github_support_docs_search" => {
548-
// Public GitHub documentation search — no private data.
549-
// S = public (empty)
550-
// I = project:github (GitHub-curated content)
551-
secrecy = vec![];
552-
baseline_scope = "github".to_string();
553-
integrity = project_github_label(ctx);
554-
}
555-
556517
_ => {
557518
// Default: inherit provided labels
558519
}

guards/github-guard/rust-guard/src/lib.rs

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -460,13 +460,7 @@ fn scope_token(scopes: &[PolicyScopeEntry]) -> String {
460460

461461
fn normalized_scope_kind(scopes: &[PolicyScopeEntry]) -> String {
462462
if scopes.len() == 1 {
463-
match scopes[0].scope_kind {
464-
ScopeKind::All => "All".to_string(),
465-
ScopeKind::Public => "Public".to_string(),
466-
ScopeKind::Owner => "Owner".to_string(),
467-
ScopeKind::Repo => "Repo".to_string(),
468-
ScopeKind::RepoPrefix => "RepoPrefix".to_string(),
469-
}
463+
scopes[0].scope_kind.to_string()
470464
} else {
471465
"Composite".to_string()
472466
}

0 commit comments

Comments
 (0)