fix(engine): auto-approve http calls with registered credentials in v2

The v1 approval flow (interactive yes/no prompt) doesn't exist in v2.
When the http tool returned UnlessAutoApproved for credentialed hosts,
the effect adapter blocked with LeaseDenied — making all skill-based
API calls fail.

Fix: credential-backed http calls bypass the v1 approval check. The
user authorized by storing the credential; the v1 interactive prompt
is redundant in v2's lease-based security model.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
This commit is contained in:
2026-03-27 22:56:50 -07:00
co-authored by Claude Opus 4.6
parent 85bcaa64e9
commit 2ce6e785e7
3 changed files with 24 additions and 9 deletions
+21 -7
View File
@@ -326,13 +326,27 @@ impl EffectExecutor for EffectBridgeAdapter {
ApprovalRequirement::UnlessAutoApproved => {
let is_approved = self.auto_approved.read().await.contains(lookup_name);
if !is_approved {
return Err(EngineError::LeaseDenied {
reason: format!(
"Tool '{}' requires approval. \
Use a read-only tool instead, or ask the user to approve this action.",
action_name
),
});
// In v2, credential-backed HTTP calls are auto-approved.
// The user authorized by storing the credential — the v1
// interactive approval flow doesn't exist in v2.
let has_credential_backing = lookup_name == "http"
&& self
.tools
.credential_registry()
.is_some_and(|reg| {
crate::tools::builtin::extract_host_from_params(&parameters)
.is_some_and(|host| reg.has_credentials_for_host(&host))
});
if !has_credential_backing {
return Err(EngineError::LeaseDenied {
reason: format!(
"Tool '{}' requires approval. \
Use a read-only tool instead, or ask the user to approve this action.",
action_name
),
});
}
}
}
ApprovalRequirement::Never => {}
+2 -1
View File
@@ -366,7 +366,8 @@ fn parse_save_to_param(save_to: Option<&serde_json::Value>) -> Result<Option<Str
}
/// Extract host from URL in params (for approval checks).
fn extract_host_from_params(params: &serde_json::Value) -> Option<String> {
/// Extract the host from an HTTP tool's params (for credential registry lookup).
pub fn extract_host_from_params(params: &serde_json::Value) -> Option<String> {
params
.get("url")
.and_then(|u| u.as_str())
+1 -1
View File
@@ -23,7 +23,7 @@ pub use extension_tools::{
ToolRemoveTool, ToolSearchTool, ToolUpgradeTool,
};
pub use file::{ApplyPatchTool, ListDirTool, ReadFileTool, WriteFileTool};
pub use http::HttpTool;
pub use http::{HttpTool, extract_host_from_params};
pub use job::{
CancelJobTool, CreateJobTool, JobEventsTool, JobPromptTool, JobStatusTool, ListJobsTool,
PromptQueue, SchedulerSlot,