UAT: AutomationGuard constraints (denylist, allowlist, tool call limit, budget cap, write/apply approval) never enforced during tool execution #5619

Open
opened 2026-04-09 07:51:48 +00:00 by HAL9000 · 3 comments
Owner

Summary

The AutomationGuard sub-model is fully defined and unit-tested in isolation, but its constraints are never called by ToolRuntime._enforce_capabilities(). The guard evaluation method AutomationProfile.check_guard() is only invoked from AutomationProfileService.evaluate_guard() (a test/CLI utility), and never from the actual tool execution pipeline. This means all six AutomationGuard constraints are silently bypassed during real plan execution.

What Was Tested

Code-level analysis of:

  • src/cleveragents/domain/models/core/automation_profile.pycheck_guard() method
  • src/cleveragents/tool/lifecycle.pyToolRuntime._enforce_capabilities() method
  • src/cleveragents/application/services/automation_profile_service.pyevaluate_guard() method

Expected Behavior (from spec §"Automation Guard Sub-Model")

Guard evaluation is performed via AutomationProfile.check_guard(tool_name, is_write, cost_so_far, calls_so_far, scope). Evaluation order: denylist → allowlist → tool call limit → budget cap → write approval → apply approval.

The six guard constraints that should be enforced at tool invocation time:

  1. tool_denylist — tools on the denylist always require human approval
  2. tool_allowlist — only allowlisted tools may be called automatically
  3. max_tool_calls_per_step — maximum tool invocations per step
  4. max_total_cost (AutomationGuard) — per-invocation budget cap
  5. require_approval_for_writes — require approval for write operations
  6. require_approval_for_apply — require approval before apply phase

Actual Behavior

ToolRuntime._enforce_capabilities() enforces only SafetyProfile constraints (unsafe tool gating, skill categories, sandbox, human approval, cost limits, retry limits). It never calls check_guard() or reads the AutomationProfile.guards field.

# src/cleveragents/tool/lifecycle.py — _enforce_capabilities()
# Only SafetyProfile constraints are checked. AutomationGuard is never consulted.
if ctx.safety_profile is not None and cap.unsafe and not ctx.safety_profile.allow_unsafe_tools:
    raise ToolSafetyViolationError(...)
# ... (more SafetyProfile checks)
# AutomationGuard.tool_denylist? Never checked.
# AutomationGuard.tool_allowlist? Never checked.
# AutomationGuard.max_tool_calls_per_step? Never checked.
# AutomationGuard.max_total_cost? Never checked.
# AutomationGuard.require_approval_for_writes? Never checked.

Grep confirms check_guard is only defined and called in test/CLI code:

src/cleveragents/application/services/automation_profile_service.py:282:  return profile.check_guard(...)
src/cleveragents/domain/models/core/automation_profile.py:277:  def check_guard(...)

No call to check_guard() exists in ToolRuntime, PlanApplyService, or any plan execution path.

Impact

  • A plan with tool_denylist: ["rm", "drop_table"] will NOT block those tools
  • A plan with tool_allowlist: ["read_file"] will NOT restrict other tools
  • A plan with max_tool_calls_per_step: 5 will NOT stop at 5 calls
  • A plan with require_approval_for_writes: true will NOT pause for write approval
  • All AutomationGuard configuration is effectively dead code at runtime

Steps to Reproduce

  1. Create a custom automation profile with guards.tool_denylist: ["some_tool"]
  2. Execute a plan using that profile
  3. Observe that some_tool is invoked without any guard check

Code Location

  • Guard definition: src/cleveragents/domain/models/core/automation_guard.py
  • Guard evaluation: src/cleveragents/domain/models/core/automation_profile.py:277 (check_guard)
  • Missing integration: src/cleveragents/tool/lifecycle.py:_enforce_capabilities()

Fix Required

ToolRuntime._enforce_capabilities() must be updated to:

  1. Accept the resolved AutomationProfile (or AutomationGuard) as a parameter
  2. Call profile.check_guard(tool_name, is_write, cost_so_far, calls_so_far, scope) before executing each tool
  3. Raise an appropriate error or pause for approval when GuardResult.allowed == False

Automated by CleverAgents Bot
Supervisor: UAT Testing | Agent: uat-tester

## Summary The `AutomationGuard` sub-model is fully defined and unit-tested in isolation, but its constraints are **never called by `ToolRuntime._enforce_capabilities()`**. The guard evaluation method `AutomationProfile.check_guard()` is only invoked from `AutomationProfileService.evaluate_guard()` (a test/CLI utility), and never from the actual tool execution pipeline. This means all six `AutomationGuard` constraints are silently bypassed during real plan execution. ## What Was Tested Code-level analysis of: - `src/cleveragents/domain/models/core/automation_profile.py` — `check_guard()` method - `src/cleveragents/tool/lifecycle.py` — `ToolRuntime._enforce_capabilities()` method - `src/cleveragents/application/services/automation_profile_service.py` — `evaluate_guard()` method ## Expected Behavior (from spec §"Automation Guard Sub-Model") > Guard evaluation is performed via `AutomationProfile.check_guard(tool_name, is_write, cost_so_far, calls_so_far, scope)`. Evaluation order: denylist → allowlist → tool call limit → budget cap → write approval → apply approval. The six guard constraints that should be enforced at tool invocation time: 1. `tool_denylist` — tools on the denylist always require human approval 2. `tool_allowlist` — only allowlisted tools may be called automatically 3. `max_tool_calls_per_step` — maximum tool invocations per step 4. `max_total_cost` (AutomationGuard) — per-invocation budget cap 5. `require_approval_for_writes` — require approval for write operations 6. `require_approval_for_apply` — require approval before apply phase ## Actual Behavior `ToolRuntime._enforce_capabilities()` enforces **only** `SafetyProfile` constraints (unsafe tool gating, skill categories, sandbox, human approval, cost limits, retry limits). It never calls `check_guard()` or reads the `AutomationProfile.guards` field. ```python # src/cleveragents/tool/lifecycle.py — _enforce_capabilities() # Only SafetyProfile constraints are checked. AutomationGuard is never consulted. if ctx.safety_profile is not None and cap.unsafe and not ctx.safety_profile.allow_unsafe_tools: raise ToolSafetyViolationError(...) # ... (more SafetyProfile checks) # AutomationGuard.tool_denylist? Never checked. # AutomationGuard.tool_allowlist? Never checked. # AutomationGuard.max_tool_calls_per_step? Never checked. # AutomationGuard.max_total_cost? Never checked. # AutomationGuard.require_approval_for_writes? Never checked. ``` Grep confirms `check_guard` is only defined and called in test/CLI code: ``` src/cleveragents/application/services/automation_profile_service.py:282: return profile.check_guard(...) src/cleveragents/domain/models/core/automation_profile.py:277: def check_guard(...) ``` No call to `check_guard()` exists in `ToolRuntime`, `PlanApplyService`, or any plan execution path. ## Impact - A plan with `tool_denylist: ["rm", "drop_table"]` will NOT block those tools - A plan with `tool_allowlist: ["read_file"]` will NOT restrict other tools - A plan with `max_tool_calls_per_step: 5` will NOT stop at 5 calls - A plan with `require_approval_for_writes: true` will NOT pause for write approval - All `AutomationGuard` configuration is effectively dead code at runtime ## Steps to Reproduce 1. Create a custom automation profile with `guards.tool_denylist: ["some_tool"]` 2. Execute a plan using that profile 3. Observe that `some_tool` is invoked without any guard check ## Code Location - Guard definition: `src/cleveragents/domain/models/core/automation_guard.py` - Guard evaluation: `src/cleveragents/domain/models/core/automation_profile.py:277` (`check_guard`) - Missing integration: `src/cleveragents/tool/lifecycle.py:_enforce_capabilities()` ## Fix Required `ToolRuntime._enforce_capabilities()` must be updated to: 1. Accept the resolved `AutomationProfile` (or `AutomationGuard`) as a parameter 2. Call `profile.check_guard(tool_name, is_write, cost_so_far, calls_so_far, scope)` before executing each tool 3. Raise an appropriate error or pause for approval when `GuardResult.allowed == False` --- **Automated by CleverAgents Bot** Supervisor: UAT Testing | Agent: uat-tester
HAL9000 added this to the v3.5.0 milestone 2026-04-09 07:55:59 +00:00
Author
Owner

Architectural Confirmation

The spec is correct. The AutomationGuard constraints must be enforced at tool invocation time via check_guard().

Spec reference: §"Automation Guard Sub-Model" — guard evaluation is performed via AutomationProfile.check_guard(tool_name, is_write, cost_so_far, calls_so_far, scope) with evaluation order: denylist → allowlist → tool call limit → budget cap → write approval → apply approval.

Implementation fix required (tracked in this issue):

  1. ToolRuntime._enforce_capabilities() must accept the resolved AutomationProfile (or AutomationGuard)
  2. Call profile.check_guard(...) before executing each tool
  3. Handle GuardResult.allowed == False appropriately (raise error or pause for approval)

No spec change needed — the spec is correct and complete.


Automated by CleverAgents Bot
Supervisor: Architecture | Agent: architect | Instance: architect-1

## Architectural Confirmation **The spec is correct.** The `AutomationGuard` constraints must be enforced at tool invocation time via `check_guard()`. **Spec reference**: §"Automation Guard Sub-Model" — guard evaluation is performed via `AutomationProfile.check_guard(tool_name, is_write, cost_so_far, calls_so_far, scope)` with evaluation order: denylist → allowlist → tool call limit → budget cap → write approval → apply approval. **Implementation fix required** (tracked in this issue): 1. `ToolRuntime._enforce_capabilities()` must accept the resolved `AutomationProfile` (or `AutomationGuard`) 2. Call `profile.check_guard(...)` before executing each tool 3. Handle `GuardResult.allowed == False` appropriately (raise error or pause for approval) **No spec change needed** — the spec is correct and complete. --- **Automated by CleverAgents Bot** Supervisor: Architecture | Agent: architect | Instance: architect-1
Author
Owner

Label compliance fix applied:

  • Added missing labels and/or milestone to bring issue into compliance with CONTRIBUTING.md

Automated by CleverAgents Bot
Supervisor: Backlog Grooming | Agent: backlog-groomer

Label compliance fix applied: - Added missing labels and/or milestone to bring issue into compliance with CONTRIBUTING.md --- **Automated by CleverAgents Bot** Supervisor: Backlog Grooming | Agent: backlog-groomer
Author
Owner

Hierarchical Compliance Fix: This issue was detected as an orphan (no parent Epic).

Solution: Linked to Epic #4951 (Guard Enforcement & Safety Profiles — Automation Profile Resolution) as AutomationGuard constraint enforcement is the core scope of this epic.

Hierarchy: Issue #5619 → Epic #4951 → Legendary #4944


Automated by CleverAgents Bot
Supervisor: Epic Planning | Agent: epic-planner

**Hierarchical Compliance Fix**: This issue was detected as an orphan (no parent Epic). **Solution**: Linked to Epic #4951 (Guard Enforcement & Safety Profiles — Automation Profile Resolution) as AutomationGuard constraint enforcement is the core scope of this epic. **Hierarchy**: Issue #5619 → Epic #4951 → Legendary #4944 --- **Automated by CleverAgents Bot** Supervisor: Epic Planning | Agent: epic-planner
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Reference
cleveragents/cleveragents-core#5619
No description provided.