Skip to content

Commit bc4b892

Browse files
authored
fix(rust-guard): handle GraphQL-format search results and bot-author filtering (#2403)
## Problem The MCP server v0.32.0+ returns search results in **two different formats**: | Format | Keys | Source | |--------|------|--------| | REST | `total_count`, `items` | Standard GitHub Search API | | GraphQL | `totalCount`, `issues`/`pull_requests`, `pageInfo` | GraphQL API | The guard only handled the REST format, causing three related failures: ### 1. Empty GraphQL search results bypass metadata handling `is_search_result_wrapper()` only checked for `total_count` (REST). GraphQL responses with `totalCount` weren't recognized as search wrappers, so empty results bypassed the server metadata handler that assigns properly-scoped `writer_integrity`. ### 2. GraphQL items not extracted in response_items.rs The legacy `response_items.rs` path only checked for the `items` key. GraphQL format uses `issues` and `pull_requests` keys, so items fell through to the single-object fallback with `none` integrity. ### 3. Empty search results with bad scope in default_labels `response_paths.rs` returned `Some(PathLabelResult)` with zero labeled paths for empty searches, bypassing `lib.rs` metadata detection. The `default_labels` used `none_integrity("")` producing `none:` tags with empty scope that never match agent DIFC tags. ## Changes - **helpers.rs**: `is_search_result_wrapper()` now detects both `total_count` and `totalCount`. Added `search_result_total_count()` helper for format-agnostic count access. - **response_items.rs**: Added `issues` and `pull_requests` key checks for item extraction. - **response_paths.rs**: Returns `None` for empty search results (defers to lib.rs metadata handler). Uses actual repo scope in `default_labels` instead of empty string. - **lib.rs**: Uses `search_result_total_count()` instead of hardcoded `total_count`. - **mod.rs**: Added 3 new tests (GraphQL format detection, total count extraction, bot-author integrity for both formats). ## Testing - 163 Rust guard tests pass (3 new) - `make agent-finished` passes (Go build, lint, unit + integration tests) Relates to github/gh-aw#22533
2 parents b8f0a6f + 8f5bfd1 commit bc4b892

5 files changed

Lines changed: 581 additions & 17 deletions

File tree

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

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -668,11 +668,22 @@ pub fn is_graphql_wrapper(response: &Value) -> bool {
668668
response.get("data").is_some()
669669
}
670670

671-
/// Returns true if the response is a search result wrapper (has "total_count").
672-
/// Used to prevent treating `{"total_count":0,"incomplete_results":false}` as a
673-
/// single data item when the search returned zero results.
671+
/// Returns true if the response is a search result wrapper.
672+
/// Handles both REST format (`total_count`) and GraphQL format (`totalCount`)
673+
/// returned by different MCP server versions. Used to prevent treating
674+
/// `{"total_count":0,"incomplete_results":false}` or
675+
/// `{"totalCount":0,"issues":[],"pageInfo":{}}` as single data items.
674676
pub fn is_search_result_wrapper(response: &Value) -> bool {
675-
response.get("total_count").is_some()
677+
response.get("total_count").is_some() || response.get("totalCount").is_some()
678+
}
679+
680+
/// Returns the total count from a search result wrapper, handling both
681+
/// REST format (`total_count`) and GraphQL format (`totalCount`).
682+
pub fn search_result_total_count(response: &Value) -> Option<u64> {
683+
response
684+
.get("total_count")
685+
.and_then(|v| v.as_u64())
686+
.or_else(|| response.get("totalCount").and_then(|v| v.as_u64()))
676687
}
677688

678689
/// Returns true if the response is an MCP content wrapper where the text was not

0 commit comments

Comments
 (0)