From 6fd17b3ab695369f94e9d94f0d0b6fd0aaaeec79 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:30:52 +0000 Subject: [PATCH 1/2] Initial plan From dc2190fa31790a8e827076cb1696b337c06d1719 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 20 Apr 2026 15:36:35 +0000 Subject: [PATCH 2/2] rust-guard: avoid static string allocations and add response path tests Agent-Logs-Url: https://github.com/github/gh-aw-mcpg/sessions/340ad058-2095-4321-8496-a3a4e25776d8 Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com> --- .../rust-guard/src/labels/response_paths.rs | 103 ++++++++++++++++++ guards/github-guard/rust-guard/src/lib.rs | 8 +- 2 files changed, 107 insertions(+), 4 deletions(-) diff --git a/guards/github-guard/rust-guard/src/labels/response_paths.rs b/guards/github-guard/rust-guard/src/labels/response_paths.rs index 6f2fdd21..798c9017 100644 --- a/guards/github-guard/rust-guard/src/labels/response_paths.rs +++ b/guards/github-guard/rust-guard/src/labels/response_paths.rs @@ -640,3 +640,106 @@ pub fn label_response_paths( // Not a collection or not supported - return None to use resource labels None } + +#[cfg(test)] +mod tests { + use super::*; + use crate::labels::constants::label_constants; + use serde_json::json; + + fn ctx() -> PolicyContext { + PolicyContext::default() + } + + #[test] + fn search_repositories_private_gets_secrecy_public_gets_empty() { + let tool_args = json!({}); + let response = json!({ + "content": [{ + "type": "text", + "text": serde_json::to_string(&json!({ + "items": [ + {"full_name": "octocat/private-repo", "private": true}, + {"full_name": "octocat/public-repo", "private": false} + ] + })) + .expect("response should serialize") + }] + }); + + let result = label_response_paths("search_repositories", &tool_args, &response, &ctx()) + .expect("should produce path labels"); + + assert_eq!(result.labeled_paths.len(), 2); + + let private_entry = &result.labeled_paths[0]; + let public_entry = &result.labeled_paths[1]; + + assert!( + !private_entry.labels.secrecy.is_empty(), + "private repo should have non-empty secrecy" + ); + assert!( + public_entry.labels.secrecy.is_empty(), + "public repo should have empty secrecy" + ); + } + + #[test] + fn list_pull_requests_merged_pr_gets_merged_integrity() { + let tool_args = json!({"owner": "octocat", "repo": "hello-world"}); + let pr = json!({ + "number": 1, + "merged_at": "2024-01-01T00:00:00Z", + "base": {"repo": {"full_name": "octocat/hello-world"}}, + "head": {"repo": {"full_name": "octocat/hello-world"}} + }); + let response = json!({ + "content": [{ + "type": "text", + "text": serde_json::to_string(&json!([pr])).expect("response should serialize") + }] + }); + + let result = label_response_paths("list_pull_requests", &tool_args, &response, &ctx()) + .expect("should produce path labels"); + assert_eq!(result.labeled_paths.len(), 1); + + let entry = &result.labeled_paths[0]; + let merged_label = format!("{}octocat/hello-world", label_constants::MERGED_PREFIX); + assert!( + entry.labels.integrity.contains(&merged_label), + "merged PR should have merged integrity; got {:?}", + entry.labels.integrity + ); + } + + #[test] + fn search_issues_uses_repo_qualifier_from_query_scope() { + let tool_args = json!({"query": "is:issue repo:octocat/hello-world bug"}); + let response = json!({ + "content": [{ + "type": "text", + "text": serde_json::to_string(&json!({ + "items": [{"number": 42}] + })) + .expect("response should serialize") + }] + }); + + let result = label_response_paths("search_issues", &tool_args, &response, &ctx()) + .expect("search_issues should produce path labels"); + + assert_eq!(result.labeled_paths.len(), 1); + assert_eq!( + result.labeled_paths[0].labels.description, + "issue:octocat/hello-world#42" + ); + } + + #[test] + fn unknown_tool_returns_none() { + let result = label_response_paths("unknown_tool", &json!({}), &json!({}), &ctx()); + assert!(result.is_none(), "unknown tool should produce no path labels"); + } +} diff --git a/guards/github-guard/rust-guard/src/lib.rs b/guards/github-guard/rust-guard/src/lib.rs index 74eaac8a..002b3939 100644 --- a/guards/github-guard/rust-guard/src/lib.rs +++ b/guards/github-guard/rust-guard/src/lib.rs @@ -209,7 +209,7 @@ pub struct ResourceLabels { #[derive(Debug, Serialize)] struct LabelResourceOutput { resource: ResourceLabels, - operation: String, + operation: &'static str, } /// Input structure for label_response @@ -314,7 +314,7 @@ enum ReposValue { #[derive(Debug, Serialize)] struct LabelAgentOutput { agent: AgentLabels, - difc_mode: String, + difc_mode: &'static str, normalized_policy: NormalizedPolicy, } @@ -567,7 +567,7 @@ pub extern "C" fn label_agent( let output = LabelAgentOutput { agent: AgentLabels { secrecy, integrity }, - difc_mode: DIFC_MODE.to_string(), + difc_mode: DIFC_MODE, normalized_policy, }; @@ -713,7 +713,7 @@ pub extern "C" fn label_resource( secrecy: final_secrecy, integrity: final_integrity, }, - operation: operation.to_string(), + operation, }; // Serialize output