feat(core): implement dynamic policy registration for subagents (#17838)

This commit is contained in:
Abhi
2026-01-30 11:57:54 -05:00
committed by GitHub
parent 94f4e027f8
commit d3bca5d97a
5 changed files with 163 additions and 34 deletions
@@ -1,27 +0,0 @@
# Priority system for policy rules:
# - Higher priority numbers win over lower priority numbers
# - When multiple rules match, the highest priority rule is applied
# - Rules are evaluated in order of priority (highest first)
#
# Priority bands (tiers):
# - Default policies (TOML): 1 + priority/1000 (e.g., priority 100 → 1.100)
# - User policies (TOML): 2 + priority/1000 (e.g., priority 100 → 2.100)
# - Admin policies (TOML): 3 + priority/1000 (e.g., priority 100 → 3.100)
#
# This ensures Admin > User > Default hierarchy is always preserved,
# while allowing user-specified priorities to work within each tier.
#
# Settings-based and dynamic rules (all in user tier 2.x):
# 2.95: Tools that the user has selected as "Always Allow" in the interactive UI
# 2.9: MCP servers excluded list (security: persistent server blocks)
# 2.4: Command line flag --exclude-tools (explicit temporary blocks)
# 2.3: Command line flag --allowed-tools (explicit temporary allows)
# 2.2: MCP servers with trust=true (persistent trusted servers)
# 2.1: MCP servers allowed list (persistent general server allows)
#
# TOML policy priorities (before transformation):
# 10: Write tools default to ASK_USER (becomes 1.010 in default tier)
# 15: Auto-edit tool override (becomes 1.015 in default tier)
# 50: Read-only tools (becomes 1.050 in default tier)
# 999: YOLO mode allow-all (becomes 1.999 in default tier)
@@ -49,8 +49,3 @@ priority = 50
toolName = "google_web_search"
decision = "allow"
priority = 50
[[rule]]
toolName = "SubagentInvocation"
decision = "allow"
priority = 50
+19 -2
View File
@@ -439,9 +439,14 @@ export class PolicyEngine {
/**
* Remove rules for a specific tool.
* If source is provided, only rules matching that source are removed.
*/
removeRulesForTool(toolName: string): void {
this.rules = this.rules.filter((rule) => rule.toolName !== toolName);
removeRulesForTool(toolName: string, source?: string): void {
this.rules = this.rules.filter(
(rule) =>
rule.toolName !== toolName ||
(source !== undefined && rule.source !== source),
);
}
/**
@@ -451,6 +456,18 @@ export class PolicyEngine {
return this.rules;
}
/**
* Check if a rule for a specific tool already exists.
* If ignoreDynamic is true, it only returns true if a rule exists that was NOT added by AgentRegistry.
*/
hasRuleForTool(toolName: string, ignoreDynamic = false): boolean {
return this.rules.some(
(rule) =>
rule.toolName === toolName &&
(!ignoreDynamic || rule.source !== 'AgentRegistry (Dynamic)'),
);
}
getCheckers(): readonly SafetyCheckerRule[] {
return this.checkers;
}