mirror of
https://github.com/outbackdingo/optimclaw.git
synced 2026-09-02 17:49:20 +00:00
refactor: consolidate tool approval into single param-aware method (#274)
* refactor: consolidate tool approval into single param-aware method Replace the two confusing approval methods (requires_approval() and requires_approval_for()) with a single requires_approval(&self, params) returning a 3-variant ApprovalRequirement enum (Never, UnlessAutoApproved, Always). This enables param-aware approval decisions: HTTP calls without auth headers now skip approval entirely, while authenticated requests always require it. Shell tool merges its destructive-command detection into the same method. Co-Authored-By: Claude Opus 4.6 <[email protected]> * feat: add credential injection to built-in HTTP tool Wire the WASM credential injection system into the built-in HTTP tool so credentials are auto-injected at the boundary (zero-exposure model). - Add SharedCredentialRegistry: thread-safe, append-only registry of credential mappings populated by WASM tools at registration time - Add credential_detect module with broad auth detection for headers (12 exact + 5 substring matches), header values (7 auth scheme prefixes), and URL query params (17 exact + 5 substring matches) - HttpTool now accepts optional credential registry + secrets store, auto-injects matching credentials in execute(), and uses broader auth detection in requires_approval() - ToolRegistry passes credential registry to HttpTool at startup and populates it when WASM tools register - Remove old hardcoded AUTH_HEADER_NAMES / has_auth_headers in favor of the new params_contain_manual_credentials() Co-Authored-By: Claude Opus 4.6 <[email protected]> * fix: address PR #274 review comments (query param injection, lock poisoning, visibility) - Fix injected query params not being sent on outbound HTTP requests by also calling .query() on the RequestBuilder alongside parsed_url mutation - Recover from poisoned RwLock in SharedCredentialRegistry instead of silently ignoring failures, with tracing::warn for visibility - Narrow inject_credential and host_matches_pattern to pub(crate) to avoid committing to them as stable public API Co-Authored-By: Claude Opus 4.6 <[email protected]> --------- Co-authored-by: Claude Opus 4.6 <[email protected]>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
542268fde5
commit
2cdd1acb1e
+35
-27
@@ -9,6 +9,25 @@ use thiserror::Error;
|
||||
|
||||
use crate::context::JobContext;
|
||||
|
||||
/// How much approval a specific tool invocation requires.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ApprovalRequirement {
|
||||
/// No approval needed.
|
||||
Never,
|
||||
/// Needs approval, but session auto-approve can bypass.
|
||||
UnlessAutoApproved,
|
||||
/// Always needs explicit approval (even if auto-approved).
|
||||
Always,
|
||||
}
|
||||
|
||||
impl ApprovalRequirement {
|
||||
/// Whether this invocation requires approval in contexts where
|
||||
/// auto-approve is irrelevant (e.g. autonomous worker/scheduler).
|
||||
pub fn is_required(&self) -> bool {
|
||||
!matches!(self, Self::Never)
|
||||
}
|
||||
}
|
||||
|
||||
/// Where a tool should execute: orchestrator process or inside a container.
|
||||
///
|
||||
/// Orchestrator tools run in the main agent process (memory access, job mgmt, etc).
|
||||
@@ -160,31 +179,14 @@ pub trait Tool: Send + Sync {
|
||||
true
|
||||
}
|
||||
|
||||
/// Whether this tool requires explicit user approval before execution.
|
||||
/// Whether this tool invocation requires user approval.
|
||||
///
|
||||
/// Returns false by default since most tools run in a sandboxed/virtualized
|
||||
/// environment. Only tools that make external network calls or perform
|
||||
/// destructive operations should return true.
|
||||
///
|
||||
/// When true, the agent will prompt the user for confirmation before
|
||||
/// executing this tool.
|
||||
fn requires_approval(&self) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Whether this specific invocation should override auto-approval.
|
||||
///
|
||||
/// This method is called after checking `requires_approval()` and finding that
|
||||
/// the tool is auto-approved for this session. Return `true` to force approval
|
||||
/// for this specific invocation despite auto-approval (for example, for
|
||||
/// destructive operations like `rm -rf` or `git push --force`).
|
||||
///
|
||||
/// Return `false` to allow auto-approval to proceed normally.
|
||||
///
|
||||
/// The default returns `false`. Override only if you need parameter-aware
|
||||
/// approval gating.
|
||||
fn requires_approval_for(&self, _params: &serde_json::Value) -> bool {
|
||||
false
|
||||
/// Returns `Never` by default (most tools run in a sandboxed environment).
|
||||
/// Override to return `UnlessAutoApproved` for tools that need approval
|
||||
/// but can be session-auto-approved, or `Always` for invocations that
|
||||
/// must always prompt (e.g. destructive shell commands, HTTP with auth).
|
||||
fn requires_approval(&self, _params: &serde_json::Value) -> ApprovalRequirement {
|
||||
ApprovalRequirement::Never
|
||||
}
|
||||
|
||||
/// Maximum time this tool is allowed to run before the caller kills it.
|
||||
@@ -347,9 +349,15 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_requires_approval_for_default() {
|
||||
fn test_requires_approval_default() {
|
||||
let tool = EchoTool;
|
||||
// Default requires_approval_for() returns false, allowing auto-approval.
|
||||
assert!(!tool.requires_approval_for(&serde_json::json!({"message": "hi"})));
|
||||
// Default requires_approval() returns Never.
|
||||
assert_eq!(
|
||||
tool.requires_approval(&serde_json::json!({"message": "hi"})),
|
||||
ApprovalRequirement::Never
|
||||
);
|
||||
assert!(!ApprovalRequirement::Never.is_required());
|
||||
assert!(ApprovalRequirement::UnlessAutoApproved.is_required());
|
||||
assert!(ApprovalRequirement::Always.is_required());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user