feat(gemini): GM-AG-001 validate auth block in agent MCP servers (#809)#817
feat(gemini): GM-AG-001 validate auth block in agent MCP servers (#809)#817
Conversation
Gemini CLI v0.39.0 added support for an `auth` block inside `mcp_servers.<name>` entries in local agent markdown frontmatter - google-gemini/gemini-cli#24770. Two variants: - type: "google-credentials" - only `scopes` allowed beyond type - type: "oauth" - client_id, client_secret, scopes, authorization_url, token_url are all optional strings/arrays Schema extracted from packages/core/src/agents/agentLoader.ts Zod definitions in the upstream PR. - New FileType::GeminiAgent variant; detection for *.md files with `agents` parent and `.gemini` grandparent. - New crates/agnix-core/src/rules/gemini_agent.rs with the GeminiAgentValidator: - Extracts YAML frontmatter between --- markers - Parses via serde_yaml (workspace dep) - Walks mcp_servers.*.auth and validates each block - Enforces discriminator, rejects unknown fields per variant, type-checks strings + arrays, validates URL shape for authorization_url + token_url - Best-effort line scanner for reporting position - 24 unit tests covering: both variant happy paths, missing type, invalid type, non-object auth, unknown field per variant, non-string client_id, malformed URL, valid URL accepted, scopes shape, per- server independent validation, disable path, URL classifier unit tests, frontmatter extractor unit tests. - Valid/invalid fixtures under tests/fixtures/{valid,invalid}/gemini-agents/. - New gemini-agents rule category + GM-AG- prefix registered in rule_parity + "Gemini Agents" label in docs generator. - total_rules 413 -> 414, validator count 41 -> 42, FileType variants 45 -> 46. Closes #809.
There was a problem hiding this comment.
Code Review
This pull request introduces a new validation rule, GM-AG-001, to verify the 'auth' block in Gemini CLI agent MCP configurations. The changes include the implementation of a new GeminiAgentValidator, detection logic for .gemini/agents/*.md files, and comprehensive updates to documentation, localization, and test fixtures. Review feedback correctly identifies a compilation risk regarding the use of unstable 'let chains' in the new validator and provides a more efficient implementation for frontmatter extraction to avoid unnecessary performance overhead.
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 1e19964. Configure here.
There was a problem hiding this comment.
Pull request overview
Adds a new Gemini CLI validator + rule (GM-AG-001) to validate the auth block under mcp_servers.<name> in local Gemini agent markdown frontmatter (.gemini/agents/*.md), aligning agnix with the gemini-cli v0.39.0 schema update.
Changes:
- Introduces
FileType::GeminiAgentwith path-based detection for.gemini/agents/*.md. - Adds
GeminiAgentValidatorimplementing GM-AG-001 (auth discriminator + per-variant field/type checks + URL/scopes validation) with unit tests and fixtures. - Updates rule inventories/docs/site counts and rule parity bookkeeping to include the new rule/category.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| website/src/data/siteData.json | Bumps totalRules to 414 for the website. |
| website/docs/rules/index.md | Updates rule count and adds GM-AG-001 to the rules index table. |
| website/docs/rules/generated/gm-ag-001.md | Adds generated documentation page for GM-AG-001. |
| tests/fixtures/valid/gemini-agents/.gemini/agents/spanner.md | Adds a valid Gemini agent fixture including an auth block. |
| tests/fixtures/invalid/gemini-agents/.gemini/agents/broken.md | Adds an invalid Gemini agent fixture with unsupported auth.type. |
| scripts/generate-docs-rules.py | Adds display label for new gemini-agents category. |
| knowledge-base/rules.json | Increments total_rules and adds the GM-AG-001 rule entry. |
| knowledge-base/VALIDATION-RULES.md | Documents the new Gemini agent rule section and GM-AG-001. |
| crates/agnix-rules/rules.json | Mirrors knowledge-base rule additions for the Rust crate. |
| crates/agnix-core/tests/api_contract.rs | Updates FileType variant coverage assertions for GeminiAgent. |
| crates/agnix-core/src/rules/mod.rs | Exposes the new gemini_agent validator module. |
| crates/agnix-core/src/rules/gemini_agent.rs | Implements GeminiAgentValidator and unit tests for GM-AG-001. |
| crates/agnix-core/src/registry.rs | Registers the new file type + validator and updates expected counts. |
| crates/agnix-core/src/file_types/types.rs | Adds FileType::GeminiAgent enum variant and Display mapping. |
| crates/agnix-core/src/file_types/detection.rs | Detects .gemini/agents/*.md as FileType::GeminiAgent. |
| crates/agnix-core/locales/en.yml | Adds i18n strings for GM-AG-001 diagnostics. |
| crates/agnix-cli/tests/rule_parity.rs | Adds category + fixtures mapping for gemini-agents. |
| README.md | Updates the headline rule count to 414. |
| CLAUDE.md | Updates rule/validator counts to reflect the new additions. |
| CHANGELOG.md | Adds an Unreleased entry describing GM-AG-001 and related plumbing. |
| AGENTS.md | Mirrors CLAUDE.md count updates (keeps parity). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- cursor: non-string `auth.type` (e.g. numeric) was reported as "missing type" because .and_then(as_str) collapses missing-key and wrong-type into the same None. Split into two diagnostics: missing stays as gm_ag_001.missing_type; non-string uses gm_ag_001.not_string with field='type'. New regression test test_non_string_type_flags_as_type_not_string. - gemini: extract_frontmatter was O(N^2) because it re-split + summed line lengths on every closing-marker hit. Rewrote to walk lines once with a running byte offset. - gemini: let-chain syntax flagged as unstable is a false positive - the workspace uses Rust edition 2024 where let-chains are stable; reply in thread.
- Rule name casing. "Invalid auth Block in Agent MCP Server" had inconsistent capitalization. Renamed to "Invalid auth block in Gemini agent MCP server" - sentence case + explicit tool name. - GeminiAgent was losing XML/Imports/CrossPlatform checks. Those previously ran on .gemini/agents/*.md via the GenericMarkdown fallback; now registered explicitly for FileType::GeminiAgent so agent body markdown keeps XML-balance + import + cross-platform validation alongside the new GM-AG-001. - Updated types.rs unit tests (display_all_variants, is_validatable_all_variants, is_generic_only_for_generic_markdown) to include both KiroSettings (from #808) and GeminiAgent so exhaustive-variant coverage is maintained. - Bumped EXPECTED_BUILTIN_COUNT 77 -> 80 and MiscProvider count 27 -> 30 for the three additional validator registrations. - disable_after_construction_removes_from_cache test updated to expect XmlValidator on 11 file types (was 10 - GeminiAgent now has it too).
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 20 out of 21 changed files in this pull request and generated 2 comments.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| let parsed: serde_yaml::Value = match serde_yaml::from_str(frontmatter_raw) { | ||
| Ok(v) => v, | ||
| Err(_) => return diagnostics, // Malformed YAML surfaced by other validators | ||
| }; |
There was a problem hiding this comment.
serde_yaml::from_str(frontmatter_raw) parse errors are silently ignored (Err(_) => return diagnostics). For FileType::GeminiAgent, the registry only runs GeminiAgentValidator + generic markdown validators (CrossPlatform/Xml/Imports), so malformed YAML frontmatter likely produces no diagnostics at all and also prevents GM-AG-001 from running. Consider emitting a diagnostic on YAML parse failure (ideally using error.location() for line/col) so users get actionable feedback when the frontmatter is syntactically invalid.
| for (idx, line) in content.lines().enumerate() { | ||
| let trimmed = line.trim_start(); | ||
| let lead_ws_len = line.len() - trimmed.len(); |
There was a problem hiding this comment.
find_auth_line scans the entire file body (for ... in content.lines()), not just the YAML frontmatter section. If the markdown body mentions mcp_servers: / server names (or contains code blocks with similar YAML), the line scanner can return a line number from outside frontmatter, producing confusing diagnostics. Consider scanning only within the extracted frontmatter (and offsetting by the frontmatter start line), or stopping the scan once the closing --- delimiter is reached.

Summary
Adds GM-AG-001 which validates the `auth` block inside `mcp_servers.` entries in Gemini CLI local agent markdown files (`.gemini/agents/*.md`). This block was added in gemini-cli v0.39.0 via google-gemini/gemini-cli#24770.
Closes
Upstream schema
From `packages/core/src/agents/agentLoader.ts` in the upstream PR:
```typescript
const mcpServerSchema = z.object({
// ... other fields ...
auth: z.union([
z.object({
type: z.literal('google-credentials'),
scopes: z.array(z.string()).optional(),
}),
z.object({
type: z.literal('oauth'),
client_id: z.string().optional(),
client_secret: z.string().optional(),
scopes: z.array(z.string()).optional(),
authorization_url: z.string().url().optional(),
token_url: z.string().url().optional(),
}),
]).optional(),
});
```
Behavior
Valid - google-credentials variant:
```yaml
mcp_servers:
spanner:
auth:
type: google-credentials
scopes:
- https://www.googleapis.com/auth/cloud-platform
```
Valid - oauth variant:
```yaml
mcp_servers:
remote:
auth:
type: oauth
client_id: abc
client_secret: xyz
scopes: [read, write]
authorization_url: https://accounts.example.com/authorize
token_url: https://accounts.example.com/token
```
Flagged:
Implementation
Test plan
Housekeeping
Follow-ups
7/7 of the rule-candidate series for v0.21.0 done! Remaining session work:
Note
Medium Risk
Adds a new
FileType::GeminiAgentand validator registration, which changes file-type detection and validation coverage for.gemini/agents/*.md; risk is moderate but scoped to new Gemini agent surfaces with extensive tests/fixtures.Overview
Adds
GM-AG-001to validate theauthblock undermcp_servers.*in Gemini CLI local agent files (.gemini/agents/*.md), enforcing thetypediscriminator (google-credentialsvsoauth), rejecting unknown fields per variant, type-checking strings/arrays, and doing basic http(s) URL sanity checks.Introduces
FileType::GeminiAgent(with detection for.gemini/agents/*.md) and wires a newGeminiAgentValidatorinto the default registry, i18n strings, and rule-parity/category plumbing; adds valid/invalid fixtures, unit tests, and regenerates rule/docs metadata (rule counts bumped413 → 414).Reviewed by Cursor Bugbot for commit 1e19964. Configure here.