Skip to content

Commit f5a8d35

Browse files
committed
feat: implement database setting for trusting tools
1 parent 560c4ae commit f5a8d35

File tree

3 files changed

+42
-0
lines changed

3 files changed

+42
-0
lines changed

crates/chat-cli/src/cli/chat/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,7 @@ impl ChatArgs {
255255
.build(os, Box::new(std::io::stderr()), !self.non_interactive)
256256
.await?;
257257
let tool_config = tool_manager.load_tools(os, &mut stderr).await?;
258+
258259
let mut tool_permissions = ToolPermissions::new(tool_config.len());
259260

260261
if self.trust_all_tools {
@@ -279,6 +280,9 @@ impl ChatArgs {
279280
tool_permissions.untrust_tool(&tool.name);
280281
}
281282
}
283+
} else {
284+
// CLI args has precendence over Database config
285+
tool_permissions.trust_from_database(&os.database);
282286
}
283287

284288
ChatSession::new(

crates/chat-cli/src/cli/chat/tools/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@ use use_aws::UseAws;
3939

4040
use super::consts::MAX_TOOL_RESPONSE_SIZE;
4141
use super::util::images::RichImageBlocks;
42+
use crate::database::Database;
43+
use crate::database::settings::Setting;
4244
use crate::os::Os;
4345

4446
/// Represents an executable tool use.
@@ -224,6 +226,15 @@ impl ToolPermissions {
224226
self.permissions.contains_key(tool_name)
225227
}
226228

229+
pub fn trust_from_database(&mut self, database: &Database) {
230+
database
231+
.settings
232+
.get_array::<String>(Setting::TrustedTools)
233+
.into_iter()
234+
.flatten()
235+
.for_each(|tool_name| self.trust_tool(&tool_name));
236+
}
237+
227238
/// Provide default permission labels for the built-in set of tools.
228239
// This "static" way avoids needing to construct a tool instance.
229240
fn default_permission_label(&self, tool_name: &str) -> String {

crates/chat-cli/src/database/settings.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ pub enum Setting {
3333
McpNoInteractiveTimeout,
3434
McpLoadedBefore,
3535
ChatDefaultModel,
36+
TrustedTools,
3637
}
3738

3839
impl AsRef<str> for Setting {
@@ -54,6 +55,7 @@ impl AsRef<str> for Setting {
5455
Self::McpNoInteractiveTimeout => "mcp.noInteractiveTimeout",
5556
Self::McpLoadedBefore => "mcp.loadedBefore",
5657
Self::ChatDefaultModel => "chat.defaultModel",
58+
Self::TrustedTools => "tools.trusted",
5759
}
5860
}
5961
}
@@ -85,6 +87,7 @@ impl TryFrom<&str> for Setting {
8587
"mcp.noInteractiveTimeout" => Ok(Self::McpNoInteractiveTimeout),
8688
"mcp.loadedBefore" => Ok(Self::McpLoadedBefore),
8789
"chat.defaultModel" => Ok(Self::ChatDefaultModel),
90+
"tools.trusted" => Ok(Self::TrustedTools),
8891
_ => Err(DatabaseError::InvalidSetting(value.to_string())),
8992
}
9093
}
@@ -150,6 +153,19 @@ impl Settings {
150153
self.get(key).and_then(|value| value.as_str().map(|s| s.into()))
151154
}
152155

156+
pub fn get_array<T>(&self, key: Setting) -> Option<Vec<T>>
157+
where
158+
T: serde::de::DeserializeOwned,
159+
{
160+
self.get(key).and_then(|value| {
161+
value.as_array().and_then(|arr| {
162+
arr.iter()
163+
.map(|v| serde_json::from_value(v.clone()).ok())
164+
.collect::<Option<Vec<T>>>()
165+
})
166+
})
167+
}
168+
153169
pub fn get_int(&self, key: Setting) -> Option<i64> {
154170
self.get(key).and_then(|value| value.as_i64())
155171
}
@@ -204,12 +220,17 @@ mod test {
204220
assert_eq!(settings.get(Setting::ShareCodeWhispererContent), None);
205221
assert_eq!(settings.get(Setting::McpLoadedBefore), None);
206222
assert_eq!(settings.get(Setting::ChatDefaultModel), None);
223+
assert_eq!(settings.get(Setting::TrustedTools), None);
207224

208225
settings.set(Setting::TelemetryEnabled, true).await.unwrap();
209226
settings.set(Setting::OldClientId, "test").await.unwrap();
210227
settings.set(Setting::ShareCodeWhispererContent, false).await.unwrap();
211228
settings.set(Setting::McpLoadedBefore, true).await.unwrap();
212229
settings.set(Setting::ChatDefaultModel, "model 1").await.unwrap();
230+
settings
231+
.set(Setting::TrustedTools, r#"["tool_a","tool_b"]"#)
232+
.await
233+
.unwrap();
213234

214235
assert_eq!(settings.get(Setting::TelemetryEnabled), Some(&Value::Bool(true)));
215236
assert_eq!(
@@ -225,15 +246,21 @@ mod test {
225246
settings.get(Setting::ChatDefaultModel),
226247
Some(&Value::String("model 1".to_string()))
227248
);
249+
assert_eq!(
250+
settings.get(Setting::TrustedTools),
251+
Some(&Value::String(r#"["tool_a","tool_b"]"#.to_string()))
252+
);
228253

229254
settings.remove(Setting::TelemetryEnabled).await.unwrap();
230255
settings.remove(Setting::OldClientId).await.unwrap();
231256
settings.remove(Setting::ShareCodeWhispererContent).await.unwrap();
232257
settings.remove(Setting::McpLoadedBefore).await.unwrap();
258+
settings.remove(Setting::TrustedTools).await.unwrap();
233259

234260
assert_eq!(settings.get(Setting::TelemetryEnabled), None);
235261
assert_eq!(settings.get(Setting::OldClientId), None);
236262
assert_eq!(settings.get(Setting::ShareCodeWhispererContent), None);
237263
assert_eq!(settings.get(Setting::McpLoadedBefore), None);
264+
assert_eq!(settings.get(Setting::TrustedTools), None);
238265
}
239266
}

0 commit comments

Comments
 (0)