Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions clawshell.example.toml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ provider = "anthropic"

# Data Loss Prevention (DLP)
# Each pattern has a name, a regex, and an action.
# action = "redact" (default): Reject the request with 400 Bad Request.
# action = "block" (default): Reject the request with 400 Bad Request.
# action = "redact": Replace matches with [REDACTED:<name>] and forward.
# scan_responses: When true, upstream responses are also scanned and PII is redacted.
[dlp]
Expand All @@ -58,7 +58,7 @@ patterns = [
# tokens (from non-streaming responses), and per-sender email-filter
# activity, and exposes them at GET /admin/stats (loopback-only).
[stats]
persist_path = "/etc/clawshell/stats.json"
persist_path = "/var/lib/clawshell/stats.json"

# Email read endpoint
# If enabled, set exactly one mode:
Expand Down
9 changes: 9 additions & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1457,11 +1457,13 @@ fn cmd_onboard() -> Result<(), Box<dyn std::error::Error>> {
// Step 2: Create necessary directories
let config_dir = PathBuf::from("/etc/clawshell");
let log_dir_path = PathBuf::from("/var/log/clawshell");
let state_dir_path = PathBuf::from("/var/lib/clawshell");

tui::print_step(2, TOTAL_STEPS, "Setting up directories...");

std::fs::create_dir_all(&config_dir)?;
std::fs::create_dir_all(&log_dir_path)?;
std::fs::create_dir_all(&state_dir_path)?;
tui::print_step_done(2, TOTAL_STEPS, "Directories created");

// Step 3: Set permissions and ownership
Expand All @@ -1488,6 +1490,13 @@ fn cmd_onboard() -> Result<(), Box<dyn std::error::Error>> {
"Failed to set log directory owner"
);
}
if let Err(error) = platform::set_owner(&state_dir_path, true) {
warn!(
error = %error,
path = %state_dir_path.display(),
"Failed to set state directory owner"
);
}
tui::print_step_done(3, TOTAL_STEPS, "Permissions set");

// Step 4: Ask the user for configuration details (TUI prompts)
Expand Down
2 changes: 1 addition & 1 deletion src/migration/targets/clawshell_toml/versions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ openai_base_url = "https://api.openai.com"
let stats = table.get("stats").unwrap().as_table().unwrap();
assert_eq!(
stats.get("persist_path").unwrap().as_str().unwrap(),
"/etc/clawshell/stats.json"
"/var/lib/clawshell/stats.json"
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/migration/targets/clawshell_toml/versions/to_v0_2_1.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ pub fn apply(
let mut stats = toml::value::Table::new();
stats.insert(
"persist_path".to_string(),
toml::Value::String("/etc/clawshell/stats.json".to_string()),
toml::Value::String("/var/lib/clawshell/stats.json".to_string()),
);
table.insert("stats".to_string(), toml::Value::Table(stats));
output.applied_steps.push(STEP_ID.to_string());
Expand Down Expand Up @@ -62,7 +62,7 @@ openai_base_url = "https://api.openai.com"
let stats = table.get("stats").unwrap().as_table().unwrap();
assert_eq!(
stats.get("persist_path").unwrap().as_str().unwrap(),
"/etc/clawshell/stats.json"
"/var/lib/clawshell/stats.json"
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/onboard/config_render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ patterns = [
]

[stats]
persist_path = "/etc/clawshell/stats.json"
persist_path = "/var/lib/clawshell/stats.json"
{oauth_providers_section}"#,
version = env!("CARGO_PKG_VERSION"),
host = config.server_host,
Expand Down Expand Up @@ -156,7 +156,7 @@ mod tests {
assert!(toml_str.contains(&format!("version = \"{}\"", env!("CARGO_PKG_VERSION"))));
assert!(toml_str.contains("[dlp]"));
assert!(toml_str.contains("[stats]"));
assert!(toml_str.contains("persist_path ="));
assert!(toml_str.contains("persist_path = \"/var/lib/clawshell/stats.json\""));
assert!(!toml_str.contains("[email]"));
assert!(!toml_str.contains("[rate_limit]"));
}
Expand Down
3 changes: 3 additions & 0 deletions src/platform/linux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ AmbientCapabilities=
RestrictAddressFamilies=AF_INET AF_INET6
UMask=0077
ReadOnlyPaths=/etc/clawshell
ReadWritePaths=/var/lib/clawshell
StandardOutput=append:/var/log/clawshell/clawshell.log
StandardError=append:/var/log/clawshell/clawshell.log

Expand Down Expand Up @@ -221,6 +222,8 @@ mod tests {
assert!(content.contains("WantedBy=multi-user.target"));
assert!(content.contains("StandardOutput=append:/var/log/clawshell/clawshell.log"));
assert!(content.contains("StandardError=append:/var/log/clawshell/clawshell.log"));
assert!(content.contains("ReadOnlyPaths=/etc/clawshell"));
assert!(content.contains("ReadWritePaths=/var/lib/clawshell"));
}

#[test]
Expand Down