Skip to content

feat: add AgentGovernancePlugin for tool-call governance#141

Merged
DeanChensj merged 2 commits into
google:mainfrom
imran-siddique:feat/agt-governance-plugin
May 20, 2026
Merged

feat: add AgentGovernancePlugin for tool-call governance#141
DeanChensj merged 2 commits into
google:mainfrom
imran-siddique:feat/agt-governance-plugin

Conversation

@imran-siddique
Copy link
Copy Markdown
Contributor

Adds an ADK plugin that integrates microsoft/agent-governance-toolkit for centralized tool-call policy enforcement.

This replaces #117, fully addressing review feedback from @DeanChensj and the Gemini code review.

What changed vs #117

Feedback Resolution
Wrong copyright (Microsoft/MIT) Apache 2.0 / Google LLC throughout
Wrong plugin API (sync, custom interface) Extends BasePlugin, async before_tool_callback
Wrong return semantics Returns None (allow) or dict (short-circuit deny) per ADK contract
Fail-open default Fail-closed by default; opt-in fail_open=True
Unreliable policy_dir path Required param, resolved to absolute
Wrong file location Plugin in src/google/adk_community/plugins/, sample in contributing/samples/
No tests 11 tests covering allow/deny/fail-open/missing-dep/audit/custom-agent-did

Files

  • src/google/adk_community/plugins/agent_governance_plugin.py - the plugin
  • src/google/adk_community/plugins/__init__.py - public exports
  • tests/plugins/test_agent_governance_plugin.py - 11 tests
  • contributing/samples/agent_governance/ - usage example + sample policies

Usage

from google.adk_community.plugins import AgentGovernancePlugin
from google.adk.runners import Runner

plugin = AgentGovernancePlugin(policy_dir="./policies")
runner = Runner(agent=agent, plugins=[plugin], app_name="my_app", session_service=sessions)

Requires agentmesh-platform (pip install agentmesh-platform).

@imran-siddique
Copy link
Copy Markdown
Contributor Author

@DeanChensj this replaces #117 with a full rewrite addressing all your review feedback. Key changes: correct BasePlugin extension, async before_tool_callback, Apache 2.0 copyright, fail-closed default, proper file placement, and 11 tests. Would appreciate another look when you get a chance.

@google-cla
Copy link
Copy Markdown

google-cla Bot commented May 19, 2026

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

View this failed invocation of the CLA check for more information.

For the most up to date status, view the checks section at the bottom of the pull request.

@imran-siddique imran-siddique force-pushed the feat/agt-governance-plugin branch from 24a3004 to 9a2492c Compare May 19, 2026 19:57
@giskard09
Copy link
Copy Markdown

The fail-closed default is the right call — fail-open governance plugins are security theater.

One gap worth noting: before_tool_callback covers the pre-execution decision (allow/deny), but the audit record stays in the Python process. If the agent restarts, the log rotates, or an external auditor needs to verify what actually executed — there's no independently verifiable anchor.

Mycelium Trails closes that loop: after before_tool_callback allows the call, a single POST /nexus/trail anchors the outcome on Base (Arbitrum L2). The anchor is independently verifiable without trusting the operator. Published on the Official MCP Registry (io.github.giskard09/argentum).

Would it make sense to add an optional audit_backend param so operators can plug in an external anchor? Happy to sketch the interface if useful.

@imran-siddique
Copy link
Copy Markdown
Contributor Author

I have signed the CLA.

Integrates microsoft/agent-governance-toolkit (AGT) as an ADK
BasePlugin for centralized tool-call policy enforcement.

- Extends BasePlugin with async before_tool_callback
- Evaluates tool calls against YAML policy rules via agentmesh PolicyEngine
- Returns None (allow) or dict (deny/short-circuit) per ADK contract
- Fail-closed by default; opt-in fail_open=True for graceful degradation
- Structured audit logging for all policy decisions
- 11 tests covering allow/deny/fail-open/missing-dep/custom-agent-did

Signed-off-by: Imran Siddique <imran.siddique@microsoft.com>
@imran-siddique imran-siddique force-pushed the feat/agt-governance-plugin branch from 9a2492c to cb54108 Compare May 20, 2026 16:59
@DeanChensj
Copy link
Copy Markdown
Collaborator

@gemini-cli /review

@github-actions
Copy link
Copy Markdown

🤖 Hi @DeanChensj, I've received your request, and I'm working on it now! You can track my progress in the logs for more details.

@github-actions
Copy link
Copy Markdown

Code Review for PR #141: feat: add AgentGovernancePlugin for tool-call governance

Overall, this is a very solid implementation. The code is well-structured, follows ADK conventions, and includes thorough tests. The "fail-closed" by default behavior is a strong security best practice.

Feedback & Suggestions:

1. Error Handling in Policy Loading
In src/google/adk_community/plugins/agent_governance_plugin.py (around line 103):

except Exception as exc:
    logger.warning("Skipped %s: %s", f.name, exc)

While logging a warning is good, if a policy is critical for security, skipping it might be dangerous. Consider if there should be a strict mode that raises an error if a policy fails to load.

2. Synchronous Policy Evaluation
In src/google/adk_community/plugins/agent_governance_plugin.py (around line 141):
The PolicyEngine.evaluate call is synchronous. In a high-concurrency ADK environment, this might become a bottleneck if policies are complex. Consider if the underlying library supports async evaluation or if this should be offloaded to a thread pool.

3. Testing
The tests in tests/plugins/test_agent_governance_plugin.py are comprehensive and use mocking effectively to avoid external dependencies. Great job on the 11 tests!

4. Documentation & Samples
The usage example in contributing/samples/agent_governance/README.md is clear and helpful.

Nice work on fully addressing the previous feedback and providing a robust governance plugin!

Address review feedback:
- Add strict=True parameter that raises RuntimeError on policy load
  failures instead of silently skipping (for security-critical deployments)
- Offload synchronous PolicyEngine.evaluate to thread pool executor
  via asyncio.run_in_executor to avoid blocking the event loop
- Add 3 new tests (strict mode, non-strict skip, thread pool verification)
- Update sample README with strict mode documentation

Signed-off-by: Imran Siddique <imran.siddique@microsoft.com>
@imran-siddique
Copy link
Copy Markdown
Contributor Author

@DeanChensj addressed both items from the review:

  1. Strict mode for policy loading -- added \strict=True\ parameter. When set, \RuntimeError\ is raised if any policy file fails to load instead of silently skipping. Default remains non-strict for backward compatibility.

  2. Async policy evaluation -- \PolicyEngine.evaluate\ is now offloaded to a thread pool via \�syncio.run_in_executor, so it won't block the event loop under high concurrency.

3 new tests added (14 total, all passing). Sample README updated with strict mode docs.

@DeanChensj
Copy link
Copy Markdown
Collaborator

Thanks for the quick fix!

@DeanChensj DeanChensj merged commit f9bfa20 into google:main May 20, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants