Restore prompt-approved tool execution in CLI parity runs

ConversationRuntime already performs permission-policy checks and interactive approvals before dispatching a tool. The CLI tool executor was routing those same tool calls back through GlobalToolRegistry::execute, which re-ran the enforcer without a prompter and flipped approved bash calls back into denials.

Add a preauthorized execution path for runtime-dispatched tools, keep registry enforcement for direct callers, and format the files that were already tripping rustfmt on main.

Constraint: CI on main was failing both cargo fmt and the mock parity harness after permission enforcement landed
Rejected: Remove registry enforcement globally | would reopen direct-dispatch permission gaps
Confidence: high
Scope-risk: narrow
Reversibility: clean
Directive: Use execute_preauthorized only after ConversationRuntime or an equivalent caller has already completed permission gating
Tested: cargo fmt --all --check; cargo test -p rusty-claude-cli; cargo test -p tools
Not-tested: Full workspace test matrix beyond the Rust CI workflow targets
This commit is contained in:
Yeachan-Heo
2026-04-03 09:32:29 +00:00
parent 618a79a9f4
commit bf59abc9e9
3 changed files with 60 additions and 23 deletions
+2 -3
View File
@@ -40,8 +40,7 @@ use plugins::{PluginHooks, PluginManager, PluginManagerConfig, PluginRegistry};
use render::{MarkdownStreamState, Spinner, TerminalRenderer};
use runtime::{
clear_oauth_credentials, generate_pkce_pair, generate_state, load_system_prompt,
parse_oauth_callback_request_target,
permission_enforcer::PermissionEnforcer,
parse_oauth_callback_request_target, permission_enforcer::PermissionEnforcer,
resolve_sandbox_status, save_oauth_credentials, ApiClient, ApiRequest, AssistantEvent,
CompactionConfig, ConfigLoader, ConfigSource, ContentBlock, ConversationMessage,
ConversationRuntime, MessageRole, OAuthAuthorizationRequest, OAuthConfig,
@@ -4976,7 +4975,7 @@ impl ToolExecutor for CliToolExecutor {
}
let value = serde_json::from_str(input)
.map_err(|error| ToolError::new(format!("invalid tool input JSON: {error}")))?;
match self.tool_registry.execute(tool_name, &value) {
match self.tool_registry.execute_preauthorized(tool_name, &value) {
Ok(output) => {
if self.emit_output {
let markdown = format_tool_result(tool_name, &output, false);