From 1537d04da4fa72b9c0b429b9a61579b859f563b9 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 2 Jun 2026 23:08:18 +0000
Subject: [PATCH 1/3] Initial plan


From a8b57f23a340b108073d0851b1505e7cc4acdb7a Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 2 Jun 2026 23:12:56 +0000
Subject: [PATCH 2/3] fix(rust-guard): sort BLOCKED_TOOLS, use binary_search,
 promote login to cfg(test)

- Sort BLOCKED_TOOLS alphabetically to match WRITE_OPERATIONS/READ_WRITE_OPERATIONS convention
- Switch is_blocked_tool to binary_search (O(log n)) instead of .contains() (O(n))
- Trim verbose redundant doc comment on is_blocked_tool to a concise one-liner
- Add blocked_tools_are_sorted test mirroring write_operations_are_sorted
- Change CollaboratorPermission.login from cfg_attr(not(test), allow(dead_code))
  to #[cfg(test)], removing the field and its two allocations from production/WASM builds
---
 .../rust-guard/src/labels/backend.rs          |  9 +++-
 guards/github-guard/rust-guard/src/tools.rs   | 42 ++++++++-----------
 2 files changed, 25 insertions(+), 26 deletions(-)

diff --git a/guards/github-guard/rust-guard/src/labels/backend.rs b/guards/github-guard/rust-guard/src/labels/backend.rs
index 2303834b8..f659f7700 100644
--- a/guards/github-guard/rust-guard/src/labels/backend.rs
+++ b/guards/github-guard/rust-guard/src/labels/backend.rs
@@ -130,7 +130,7 @@ pub struct IssueAuthorInfo {
 #[derive(Debug, Clone)]
 pub struct CollaboratorPermission {
     pub permission: Option<String>,
-    #[cfg_attr(not(test), allow(dead_code))]
+    #[cfg(test)]
     pub login: Option<String>,
 }
 
@@ -494,6 +494,7 @@ pub fn get_collaborator_permission_with_callback(
         ));
         return cached.map(|permission| CollaboratorPermission {
             permission: Some(permission),
+            #[cfg(test)]
             login: Some(username.to_string()),
         });
     }
@@ -572,7 +573,11 @@ pub fn get_collaborator_permission_with_callback(
 
     set_cached_collaborator_permission(&cache_key, permission.clone());
 
-    Some(CollaboratorPermission { permission, login })
+    Some(CollaboratorPermission {
+        permission,
+        #[cfg(test)]
+        login,
+    })
 }
 
 pub fn get_collaborator_permission(
diff --git a/guards/github-guard/rust-guard/src/tools.rs b/guards/github-guard/rust-guard/src/tools.rs
index d684fa977..92e90c6bc 100644
--- a/guards/github-guard/rust-guard/src/tools.rs
+++ b/guards/github-guard/rust-guard/src/tools.rs
@@ -137,36 +137,19 @@ pub fn is_unlock_operation(tool_name: &str) -> bool {
 
 /// Tools that are unconditionally blocked regardless of agent integrity.
 ///
-/// These operations are too dangerous or unsupported to ever permit via an agent.
-/// Entries here should also appear in `WRITE_OPERATIONS` or `READ_WRITE_OPERATIONS`
-/// so the tool is still subject to all normal write-path checks before being denied.
+/// Keep sorted for `binary_search` correctness (see `blocked_tools_are_sorted` test).
+/// Entries here should also appear in `WRITE_OPERATIONS` or `READ_WRITE_OPERATIONS`.
 pub const BLOCKED_TOOLS: &[&str] = &[
-    "transfer_repository",  // irreversible ownership transfer
     "archive_repository",   // repo settings change; unsupported
-    "unarchive_repository", // symmetric to archive_repository
-    "rename_repository",    // breaks clone URLs and integrations
     "create_agent_task",    // unsupported agent-task creation
+    "rename_repository",    // breaks clone URLs and integrations
+    "transfer_repository",  // irreversible ownership transfer
+    "unarchive_repository", // symmetric to archive_repository
 ];
 
-/// Check if a tool is unconditionally blocked (always denied regardless of agent integrity).
-///
-/// Blocked tools are listed here when the operation is considered too dangerous
-/// to ever permit via an agent, even if the agent would otherwise satisfy the
-/// integrity requirements for a normal write operation.
-///
-/// 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.
-/// - `create_agent_task`: creates a Copilot coding-agent job that opens a branch and PR;
-///   unsupported as a directly invocable agent operation.
+/// Returns `true` if `tool_name` is in [`BLOCKED_TOOLS`] — denied regardless of agent integrity.
 pub fn is_blocked_tool(tool_name: &str) -> bool {
-    BLOCKED_TOOLS.contains(&tool_name)
+    BLOCKED_TOOLS.binary_search(&tool_name).is_ok()
 }
 
 #[cfg(test)]
@@ -205,6 +188,17 @@ mod tests {
         );
     }
 
+    #[test]
+    fn blocked_tools_are_sorted() {
+        let mut sorted = BLOCKED_TOOLS.to_vec();
+        sorted.sort_unstable();
+        assert_eq!(
+            BLOCKED_TOOLS,
+            sorted.as_slice(),
+            "BLOCKED_TOOLS must be kept in sorted order for binary_search correctness"
+        );
+    }
+
     #[test]
     fn test_is_blocked_tool_transfer_repository() {
         assert!(

From aded48d0d28616aaed5dc055b20210c996866e52 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Tue, 2 Jun 2026 23:27:08 +0000
Subject: [PATCH 3/3] rust-guard: gate login extraction and log reference
 behind #[cfg(test)]

---
 guards/github-guard/rust-guard/src/labels/backend.rs | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/guards/github-guard/rust-guard/src/labels/backend.rs b/guards/github-guard/rust-guard/src/labels/backend.rs
index f659f7700..4d6169d4a 100644
--- a/guards/github-guard/rust-guard/src/labels/backend.rs
+++ b/guards/github-guard/rust-guard/src/labels/backend.rs
@@ -560,12 +560,19 @@ pub fn get_collaborator_permission_with_callback(
         .and_then(|v| v.as_str())
         .map(String::from);
 
+    #[cfg(test)]
     let login = data
         .get("user")
         .and_then(|u| u.get("login"))
         .and_then(|v| v.as_str())
         .map(String::from);
 
+    #[cfg(not(test))]
+    crate::log_info(&format!(
+        "get_collaborator_permission: {}/{} user {} → permission={:?}",
+        owner, repo, username, permission
+    ));
+    #[cfg(test)]
     crate::log_info(&format!(
         "get_collaborator_permission: {}/{} user {} → permission={:?} login={:?}",
         owner, repo, username, permission, login
