From 4618e21683eab954dd99b19fc0881abc73d0fc6c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 29 Mar 2026 23:40:23 +0000 Subject: [PATCH 1/2] Initial plan From aadb2150de64cff9893bea8f39de1b6c86d7ce8e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 29 Mar 2026 23:46:56 +0000 Subject: [PATCH 2/2] Guard coverage: block all modifying gh repo operations (rename/unarchive/archive) - Add `unarchive_repository` and `rename_repository` to WRITE_OPERATIONS - Block `archive_repository`, `unarchive_repository`, `rename_repository` in is_blocked_tool() alongside the existing `transfer_repository` entry - Add match arms in tool_rules.rs for the three new blocked operations (repo-visibility secrecy, same pattern as transfer_repository) - Add tests for newly blocked and write-classified operations Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/844d1229-ef7e-493a-a187-398e882d4f68 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- .../rust-guard/src/labels/tool_rules.rs | 10 +++++ guards/github-guard/rust-guard/src/tools.rs | 45 ++++++++++++++++--- 2 files changed, 49 insertions(+), 6 deletions(-) diff --git a/guards/github-guard/rust-guard/src/labels/tool_rules.rs b/guards/github-guard/rust-guard/src/labels/tool_rules.rs index aed07eb9..f7455cba 100644 --- a/guards/github-guard/rust-guard/src/labels/tool_rules.rs +++ b/guards/github-guard/rust-guard/src/labels/tool_rules.rs @@ -171,6 +171,16 @@ pub fn apply_tool_labels( secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx); } + // === Modifying Repository Operations (blocked: unsupported gh repo operations) === + "archive_repository" | "unarchive_repository" | "rename_repository" => { + // All modifying `gh repo` operations (archive, unarchive, rename) are treated as + // unsupported for automated agents — the same policy as transfer_repository. + // Blocking is enforced in label_resource via is_blocked_tool(); this arm applies + // repo-visibility secrecy so the resource is correctly classified before the + // integrity override happens in label_resource. + secrecy = apply_repo_visibility_secrecy(&owner, &repo, repo_id, secrecy, ctx); + } + // Search issues: extract repo scope from query or tool_args when available "search_issues" => { let (s_owner, s_repo, s_repo_id) = resolve_search_scope(tool_args, &owner, &repo); diff --git a/guards/github-guard/rust-guard/src/tools.rs b/guards/github-guard/rust-guard/src/tools.rs index 89f4ae3f..35e3bc6d 100644 --- a/guards/github-guard/rust-guard/src/tools.rs +++ b/guards/github-guard/rust-guard/src/tools.rs @@ -38,11 +38,13 @@ pub const WRITE_OPERATIONS: &[&str] = &[ // Dynamically enables additional toolsets, expanding the agent's capability set "enable_toolset", // Pre-emptive entries for anticipated future MCP tools (no equivalent tool today) - "archive_repository", // gh repo archive - "transfer_issue", // gh issue transfer - "transfer_repository", // gh repo transfer — blocked: repo ownership transfer is irreversible - "pin_issue", // gh issue pin - "unpin_issue", // gh issue unpin + "archive_repository", // gh repo archive — blocked: repo settings change unsupported + "unarchive_repository", // gh repo unarchive — blocked: symmetric to archive_repository + "rename_repository", // gh repo rename — blocked: breaks clone URLs and integrations + "transfer_issue", // gh issue transfer + "transfer_repository", // gh repo transfer — blocked: repo ownership transfer is irreversible + "pin_issue", // gh issue pin + "unpin_issue", // gh issue unpin "enable_workflow", // gh workflow enable "disable_workflow", // gh workflow disable "set_secret", // gh secret set @@ -116,8 +118,17 @@ pub fn is_unlock_operation(tool_name: &str) -> bool { /// Current entries: /// - `transfer_repository`: repository ownership transfer is irreversible and /// must never be performed by an automated agent. +/// - `archive_repository`: archives a repository, restricting contributions; unsupported as an +/// agent operation. +/// - `unarchive_repository`: re-enables contributions to a previously archived repository; +/// symmetric to `archive_repository` and equally unsupported. +/// - `rename_repository`: renames a repository, breaking all clone URLs, webhooks, and external +/// references; unsupported as an agent operation. pub fn is_blocked_tool(tool_name: &str) -> bool { - matches!(tool_name, "transfer_repository") + matches!( + tool_name, + "transfer_repository" | "archive_repository" | "unarchive_repository" | "rename_repository" + ) } #[cfg(test)] @@ -132,6 +143,17 @@ mod tests { ); } + #[test] + fn test_is_blocked_tool_repo_modifying_operations() { + for op in &["archive_repository", "unarchive_repository", "rename_repository"] { + assert!( + is_blocked_tool(op), + "{} must be unconditionally blocked (modifying gh repo operation)", + op + ); + } + } + #[test] fn test_is_blocked_tool_other_write_ops_not_blocked() { // Regular write operations should not be blocked @@ -152,6 +174,17 @@ mod tests { ); } + #[test] + fn test_repo_modifying_operations_are_write_operations() { + for op in &["archive_repository", "unarchive_repository", "rename_repository"] { + assert!( + is_write_operation(op), + "{} must be classified as a write operation", + op + ); + } + } + #[test] fn test_pin_unpin_issue_are_write_operations() { assert!(