1use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9
10#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
12#[serde(rename_all = "camelCase", default)]
13pub struct GatewayConfig {
14 #[serde(skip_serializing_if = "Option::is_none")]
15 pub bind: Option<String>,
16 #[serde(skip_serializing_if = "Option::is_none")]
17 pub port: Option<u16>,
18 #[serde(skip_serializing_if = "Option::is_none")]
20 pub auth_token: Option<String>,
21 #[serde(skip_serializing_if = "Option::is_none")]
22 pub auth: Option<GatewayAuth>,
23 #[serde(skip_serializing_if = "Option::is_none")]
24 pub tls: Option<TlsConfig>,
25 #[serde(skip_serializing_if = "Option::is_none")]
26 pub mdns: Option<MdnsConfig>,
27 #[serde(skip_serializing_if = "Option::is_none")]
28 pub control_ui: Option<ControlUiConfig>,
29 #[serde(skip_serializing_if = "Option::is_none")]
30 pub trusted_proxies: Option<Vec<String>>,
31}
32
33#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
34#[serde(rename_all = "camelCase", default)]
35pub struct GatewayAuth {
36 #[serde(skip_serializing_if = "Option::is_none")]
37 pub mode: Option<String>,
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub token: Option<String>,
40 #[serde(skip_serializing_if = "Option::is_none")]
41 pub password: Option<String>,
42}
43
44#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
45#[serde(rename_all = "camelCase", default)]
46pub struct TlsConfig {
47 #[serde(skip_serializing_if = "Option::is_none")]
48 pub enabled: Option<bool>,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 pub cert: Option<String>,
51 #[serde(skip_serializing_if = "Option::is_none")]
52 pub key: Option<String>,
53}
54
55#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
56#[serde(rename_all = "camelCase", default)]
57pub struct MdnsConfig {
58 #[serde(skip_serializing_if = "Option::is_none")]
59 pub mode: Option<String>,
60}
61
62#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
63#[serde(rename_all = "camelCase", default)]
64pub struct ControlUiConfig {
65 #[serde(skip_serializing_if = "Option::is_none")]
66 pub dangerously_disable_device_auth: Option<bool>,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub allow_insecure_auth: Option<bool>,
69}
70
71#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
73#[serde(rename_all = "camelCase", default)]
74pub struct ExecConfig {
75 #[serde(skip_serializing_if = "Option::is_none")]
76 pub approvals: Option<String>,
77 #[serde(skip_serializing_if = "Option::is_none")]
78 pub auto_approve: Option<Vec<String>>,
79}
80
81#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
83#[serde(rename_all = "camelCase", default)]
84pub struct SandboxConfig {
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub mode: Option<String>,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub scope: Option<String>,
89 #[serde(skip_serializing_if = "Option::is_none")]
90 pub workspace_access: Option<String>,
91}
92
93#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
95#[serde(rename_all = "camelCase", default)]
96pub struct ToolsConfig {
97 #[serde(skip_serializing_if = "Option::is_none")]
98 pub exec: Option<ToolsExec>,
99}
100
101#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
102#[serde(rename_all = "camelCase", default)]
103pub struct ToolsExec {
104 #[serde(skip_serializing_if = "Option::is_none")]
105 pub host: Option<String>,
106}
107
108#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
110#[serde(rename_all = "camelCase", default)]
111pub struct SessionConfig {
112 #[serde(skip_serializing_if = "Option::is_none")]
113 pub dm_scope: Option<String>,
114}
115
116#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
118#[serde(rename_all = "camelCase", default)]
119pub struct LoggingConfig {
120 #[serde(skip_serializing_if = "Option::is_none")]
121 pub redact_sensitive: Option<String>,
122}
123
124#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
126#[serde(rename_all = "snake_case")]
127pub enum FailureMode {
128 BlockAll,
129 SafeMode,
130 ReadOnly,
131}
132
133#[derive(Serialize, Deserialize, Clone, Copy, Debug, PartialEq, Eq)]
135#[serde(rename_all = "lowercase")]
136pub enum RiskProfile {
137 Strict,
138 Standard,
139 Permissive,
140}
141
142#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
144#[serde(rename_all = "camelCase", default)]
145pub struct SecureOpsConfig {
146 #[serde(skip_serializing_if = "Option::is_none")]
147 pub monitors: Option<MonitorsToggle>,
148 #[serde(skip_serializing_if = "Option::is_none")]
149 pub cost: Option<CostLimits>,
150 #[serde(skip_serializing_if = "Option::is_none")]
151 pub memory: Option<MemorySettings>,
152 #[serde(skip_serializing_if = "Option::is_none")]
153 pub skills: Option<SkillsSettings>,
154 #[serde(skip_serializing_if = "Option::is_none")]
155 pub network: Option<NetworkSettings>,
156 #[serde(skip_serializing_if = "Option::is_none")]
157 pub failure_mode: Option<FailureMode>,
158 #[serde(skip_serializing_if = "Option::is_none")]
159 pub risk_profile: Option<RiskProfile>,
160 #[serde(skip_serializing_if = "Option::is_none")]
161 pub risk_profiles: Option<HashMap<String, RiskProfileDef>>,
162 #[serde(skip_serializing_if = "Option::is_none")]
163 pub behavioral: Option<BehavioralSettings>,
164}
165
166#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
167#[serde(rename_all = "camelCase", default)]
168pub struct MonitorsToggle {
169 #[serde(skip_serializing_if = "Option::is_none")]
170 pub credentials: Option<bool>,
171 #[serde(skip_serializing_if = "Option::is_none")]
172 pub memory: Option<bool>,
173 #[serde(skip_serializing_if = "Option::is_none")]
174 pub skills: Option<bool>,
175 #[serde(skip_serializing_if = "Option::is_none")]
176 pub cost: Option<bool>,
177}
178
179#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
180#[serde(rename_all = "camelCase", default)]
181pub struct CostLimits {
182 #[serde(skip_serializing_if = "Option::is_none")]
183 pub hourly_limit_usd: Option<f64>,
184 #[serde(skip_serializing_if = "Option::is_none")]
185 pub daily_limit_usd: Option<f64>,
186 #[serde(skip_serializing_if = "Option::is_none")]
187 pub monthly_limit_usd: Option<f64>,
188 #[serde(skip_serializing_if = "Option::is_none")]
189 pub circuit_breaker_enabled: Option<bool>,
190}
191
192#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
193#[serde(rename_all = "camelCase", default)]
194pub struct MemorySettings {
195 #[serde(skip_serializing_if = "Option::is_none")]
196 pub integrity_checks: Option<bool>,
197 #[serde(skip_serializing_if = "Option::is_none")]
198 pub prompt_injection_scan: Option<bool>,
199 #[serde(skip_serializing_if = "Option::is_none")]
200 pub quarantine_enabled: Option<bool>,
201 #[serde(skip_serializing_if = "Option::is_none")]
202 pub trust_levels: Option<bool>,
203}
204
205#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
206#[serde(rename_all = "camelCase", default)]
207pub struct SkillsSettings {
208 #[serde(skip_serializing_if = "Option::is_none")]
209 pub block_unaudited: Option<bool>,
210 #[serde(skip_serializing_if = "Option::is_none")]
211 pub scan_on_install: Option<bool>,
212 #[serde(skip_serializing_if = "Option::is_none")]
213 pub ioc_check_enabled: Option<bool>,
214}
215
216#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
217#[serde(rename_all = "camelCase", default)]
218pub struct NetworkSettings {
219 #[serde(skip_serializing_if = "Option::is_none")]
220 pub egress_allowlist_enabled: Option<bool>,
221 #[serde(skip_serializing_if = "Option::is_none")]
222 pub egress_allowlist: Option<Vec<String>>,
223}
224
225#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
226#[serde(rename_all = "camelCase", default)]
227pub struct RiskProfileDef {
228 #[serde(skip_serializing_if = "Option::is_none")]
229 pub failure_mode: Option<FailureMode>,
230 #[serde(skip_serializing_if = "Option::is_none")]
231 pub approval_required: Option<bool>,
232 #[serde(skip_serializing_if = "Option::is_none")]
233 pub allowed_tools: Option<Vec<String>>,
234 #[serde(skip_serializing_if = "Option::is_none")]
235 pub blocked_tools: Option<Vec<String>>,
236 #[serde(skip_serializing_if = "Option::is_none")]
237 pub max_cost_per_session: Option<f64>,
238}
239
240#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
241#[serde(rename_all = "camelCase", default)]
242pub struct BehavioralSettings {
243 #[serde(skip_serializing_if = "Option::is_none")]
244 pub baseline_enabled: Option<bool>,
245 #[serde(skip_serializing_if = "Option::is_none")]
246 pub deviation_threshold: Option<f64>,
247 #[serde(skip_serializing_if = "Option::is_none")]
248 pub window_minutes: Option<u64>,
249}
250
251#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
253#[serde(rename_all = "camelCase", default)]
254pub struct OpenClawConfig {
255 #[serde(skip_serializing_if = "Option::is_none")]
256 pub gateway: Option<GatewayConfig>,
257 #[serde(skip_serializing_if = "Option::is_none")]
258 pub exec: Option<ExecConfig>,
259 #[serde(skip_serializing_if = "Option::is_none")]
260 pub sandbox: Option<SandboxConfig>,
261 #[serde(skip_serializing_if = "Option::is_none")]
262 pub tools: Option<ToolsConfig>,
263 #[serde(skip_serializing_if = "Option::is_none")]
264 pub session: Option<SessionConfig>,
265 #[serde(skip_serializing_if = "Option::is_none")]
266 pub logging: Option<LoggingConfig>,
267 #[serde(skip_serializing_if = "Option::is_none")]
268 pub secureops: Option<SecureOpsConfig>,
269}
270
271impl OpenClawConfig {
272 pub fn failure_mode(&self) -> FailureMode {
275 self.secureops
276 .as_ref()
277 .and_then(|s| s.failure_mode)
278 .unwrap_or(FailureMode::BlockAll)
279 }
280
281 pub fn risk_profile(&self) -> RiskProfile {
284 self.secureops
285 .as_ref()
286 .and_then(|s| s.risk_profile)
287 .unwrap_or(RiskProfile::Standard)
288 }
289}
290
291#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
294#[serde(rename_all = "snake_case", default)]
295pub struct DockerServiceConfig {
296 #[serde(skip_serializing_if = "Option::is_none")]
297 pub read_only: Option<bool>,
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub cap_drop: Option<Vec<String>>,
300 #[serde(skip_serializing_if = "Option::is_none")]
301 pub security_opt: Option<Vec<String>>,
302 #[serde(skip_serializing_if = "Option::is_none")]
303 pub networks: Option<Vec<String>>,
304 #[serde(skip_serializing_if = "Option::is_none")]
305 pub network_mode: Option<String>,
306 #[serde(skip_serializing_if = "Option::is_none")]
307 pub volumes: Option<Vec<String>>,
308 #[serde(skip_serializing_if = "Option::is_none")]
309 pub deploy: Option<DockerDeploy>,
310}
311
312#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
313#[serde(rename_all = "snake_case", default)]
314pub struct DockerDeploy {
315 #[serde(skip_serializing_if = "Option::is_none")]
316 pub resources: Option<DockerResources>,
317}
318
319#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
320#[serde(rename_all = "snake_case", default)]
321pub struct DockerResources {
322 #[serde(skip_serializing_if = "Option::is_none")]
323 pub limits: Option<DockerLimits>,
324}
325
326#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
327#[serde(rename_all = "snake_case", default)]
328pub struct DockerLimits {
329 #[serde(skip_serializing_if = "Option::is_none")]
330 pub memory: Option<String>,
331 #[serde(skip_serializing_if = "Option::is_none")]
332 pub cpus: Option<String>,
333}
334
335#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
336#[serde(rename_all = "snake_case", default)]
337pub struct DockerNetwork {
338 #[serde(skip_serializing_if = "Option::is_none")]
339 pub driver: Option<String>,
340 #[serde(skip_serializing_if = "Option::is_none")]
341 pub internal: Option<bool>,
342}
343
344#[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq)]
345#[serde(rename_all = "snake_case", default)]
346pub struct DockerComposeConfig {
347 #[serde(skip_serializing_if = "Option::is_none")]
348 pub services: Option<HashMap<String, DockerServiceConfig>>,
349 #[serde(skip_serializing_if = "Option::is_none")]
350 pub networks: Option<HashMap<String, DockerNetwork>>,
351}