From 81d3b72e343863eb787a88921cf51ef83d9e0b57 Mon Sep 17 00:00:00 2001 From: thibaud-leclere Date: Mon, 13 Apr 2026 10:16:44 +0200 Subject: [PATCH] fix: address code review issues (mutex safety, schema, CSP, error handling) - Replace .unwrap() on Mutex lock with proper error propagation - Add worktree_path and branch_name columns to processed_tickets - Add style-src to CSP for Tailwind compatibility - Implement std::error::Error for AppError - Check affected row count in update/delete operations - Handle non-UTF-8 paths in git clone Co-Authored-By: Claude Opus 4.6 (1M context) --- src-tauri/migrations/001_init.sql | 2 ++ src-tauri/src/commands/project.rs | 15 +++++++++------ src-tauri/src/error.rs | 2 ++ src-tauri/src/models/project.rs | 10 ++++++++-- src-tauri/tauri.conf.json | 2 +- 5 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src-tauri/migrations/001_init.sql b/src-tauri/migrations/001_init.sql index 68a33e0..ea1a332 100644 --- a/src-tauri/migrations/001_init.sql +++ b/src-tauri/migrations/001_init.sql @@ -34,6 +34,8 @@ CREATE TABLE IF NOT EXISTS processed_tickets ( status TEXT NOT NULL DEFAULT 'Pending', analyst_report TEXT, developer_report TEXT, + worktree_path TEXT, + branch_name TEXT, detected_at TEXT NOT NULL DEFAULT (datetime('now')), processed_at TEXT ); diff --git a/src-tauri/src/commands/project.rs b/src-tauri/src/commands/project.rs index f7c18b4..8e744ac 100644 --- a/src-tauri/src/commands/project.rs +++ b/src-tauri/src/commands/project.rs @@ -20,8 +20,11 @@ pub fn create_project( let clone_dir = home.join("orchai-repos").join(&name); std::fs::create_dir_all(&clone_dir)?; + let clone_dir_str = clone_dir.to_str() + .ok_or_else(|| AppError::from("Clone path contains invalid characters".to_string()))?; + let output = Command::new("git") - .args(["clone", &path_or_url, clone_dir.to_str().unwrap()]) + .args(["clone", &path_or_url, clone_dir_str]) .output()?; if !output.status.success() { @@ -41,21 +44,21 @@ pub fn create_project( (path_or_url, None) }; - let db = state.db.lock().unwrap(); + let db = state.db.lock().map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?; let project = Project::insert(&db, &name, &local_path, cloned_from.as_deref(), &base_branch)?; Ok(project) } #[tauri::command] pub fn list_projects(state: State<'_, AppState>) -> Result, AppError> { - let db = state.db.lock().unwrap(); + let db = state.db.lock().map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?; let projects = Project::list(&db)?; Ok(projects) } #[tauri::command] pub fn get_project(state: State<'_, AppState>, id: String) -> Result { - let db = state.db.lock().unwrap(); + let db = state.db.lock().map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?; let project = Project::get_by_id(&db, &id)?; Ok(project) } @@ -67,14 +70,14 @@ pub fn update_project( name: String, base_branch: String, ) -> Result<(), AppError> { - let db = state.db.lock().unwrap(); + let db = state.db.lock().map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?; Project::update(&db, &id, &name, &base_branch)?; Ok(()) } #[tauri::command] pub fn delete_project(state: State<'_, AppState>, id: String) -> Result<(), AppError> { - let db = state.db.lock().unwrap(); + let db = state.db.lock().map_err(|e| AppError::from(format!("Database lock failed: {}", e)))?; Project::delete(&db, &id)?; Ok(()) } diff --git a/src-tauri/src/error.rs b/src-tauri/src/error.rs index 7b33c2f..e0629c1 100644 --- a/src-tauri/src/error.rs +++ b/src-tauri/src/error.rs @@ -32,3 +32,5 @@ impl std::fmt::Display for AppError { write!(f, "{}", self.message) } } + +impl std::error::Error for AppError {} diff --git a/src-tauri/src/models/project.rs b/src-tauri/src/models/project.rs index 66f4f2b..e91dba9 100644 --- a/src-tauri/src/models/project.rs +++ b/src-tauri/src/models/project.rs @@ -73,15 +73,21 @@ impl Project { } pub fn update(conn: &Connection, id: &str, name: &str, base_branch: &str) -> Result<()> { - conn.execute( + let affected = conn.execute( "UPDATE projects SET name = ?1, base_branch = ?2 WHERE id = ?3", params![name, base_branch, id], )?; + if affected == 0 { + return Err(rusqlite::Error::QueryReturnedNoRows); + } Ok(()) } pub fn delete(conn: &Connection, id: &str) -> Result<()> { - conn.execute("DELETE FROM projects WHERE id = ?1", params![id])?; + let affected = conn.execute("DELETE FROM projects WHERE id = ?1", params![id])?; + if affected == 0 { + return Err(rusqlite::Error::QueryReturnedNoRows); + } Ok(()) } } diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index c4654e5..aa68e57 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -18,7 +18,7 @@ } ], "security": { - "csp": "default-src 'self'; script-src 'self'; connect-src ipc: http://ipc.localhost" + "csp": "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'; connect-src ipc: http://ipc.localhost" } }, "bundle": {