Skip to content

Commit c2b28dd

Browse files
Copilotlpcox
andauthored
fix(guard): preserve github baseline scope for notification and repo-creation writes
Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/0114d8b5-ccf7-4dee-b9d7-630f4545b568 Co-authored-by: lpcox <[email protected]>
1 parent 1d85709 commit c2b28dd

1 file changed

Lines changed: 74 additions & 0 deletions

File tree

  • guards/github-guard/rust-guard/src

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

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,12 @@ fn infer_scope_for_baseline(tool_name: &str, tool_args: &Value, repo_id: &str) -
262262
}
263263

264264
match tool_name {
265+
"dismiss_notification"
266+
| "mark_all_notifications_read"
267+
| "manage_notification_subscription"
268+
| "manage_repository_notification_subscription"
269+
| "create_repository"
270+
| "fork_repository" => "github".to_string(),
265271
"search_code" | "search_issues" | "search_pull_requests" => {
266272
let query = tool_args
267273
.get("query")
@@ -1159,6 +1165,74 @@ mod tests {
11591165
assert_eq!(inferred, "github/gh-aw-mcpg");
11601166
}
11611167

1168+
#[test]
1169+
fn infer_scope_for_baseline_uses_github_scope_for_notification_management_tools() {
1170+
let tool_args = json!({ "threadId": "123" });
1171+
for tool in &[
1172+
"dismiss_notification",
1173+
"mark_all_notifications_read",
1174+
"manage_notification_subscription",
1175+
"manage_repository_notification_subscription",
1176+
] {
1177+
let inferred = infer_scope_for_baseline(tool, &tool_args, "");
1178+
assert_eq!(inferred, "github", "{} should infer github baseline scope", tool);
1179+
}
1180+
}
1181+
1182+
#[test]
1183+
fn infer_scope_for_baseline_uses_github_scope_for_repo_creation_tools() {
1184+
let tool_args = json!({ "name": "new-repo" });
1185+
for tool in &["create_repository", "fork_repository"] {
1186+
let inferred = infer_scope_for_baseline(tool, &tool_args, "");
1187+
assert_eq!(inferred, "github", "{} should infer github baseline scope", tool);
1188+
}
1189+
}
1190+
1191+
#[test]
1192+
fn notification_management_integrity_preserved_after_baseline() {
1193+
let ctx = PolicyContext::default();
1194+
let tool_args = json!({ "threadId": "123" });
1195+
for tool in &[
1196+
"dismiss_notification",
1197+
"mark_all_notifications_read",
1198+
"manage_notification_subscription",
1199+
"manage_repository_notification_subscription",
1200+
] {
1201+
let (_, integrity, _) =
1202+
labels::apply_tool_labels(tool, &tool_args, "", vec![], vec![], String::new(), &ctx);
1203+
let baseline_scope = infer_scope_for_baseline(tool, &tool_args, "");
1204+
let after_baseline =
1205+
labels::ensure_integrity_baseline(&baseline_scope, integrity, &ctx);
1206+
1207+
assert_eq!(
1208+
after_baseline,
1209+
labels::project_github_label(&ctx),
1210+
"{} integrity should remain github-scoped after baseline enforcement",
1211+
tool
1212+
);
1213+
}
1214+
}
1215+
1216+
#[test]
1217+
fn repo_creation_integrity_preserved_after_baseline() {
1218+
let ctx = PolicyContext::default();
1219+
let tool_args = json!({ "name": "new-repo" });
1220+
for tool in &["create_repository", "fork_repository"] {
1221+
let (_, integrity, _) =
1222+
labels::apply_tool_labels(tool, &tool_args, "", vec![], vec![], String::new(), &ctx);
1223+
let baseline_scope = infer_scope_for_baseline(tool, &tool_args, "");
1224+
let after_baseline =
1225+
labels::ensure_integrity_baseline(&baseline_scope, integrity, &ctx);
1226+
1227+
assert_eq!(
1228+
after_baseline,
1229+
labels::writer_integrity("github", &ctx),
1230+
"{} integrity should remain github writer-scoped after baseline enforcement",
1231+
tool
1232+
);
1233+
}
1234+
}
1235+
11621236
#[test]
11631237
fn transfer_repository_integrity_is_blocked_after_ensure_baseline() {
11641238
// Verify that the is_blocked_tool + blocked_integrity override logic produces

0 commit comments

Comments
 (0)