Skip to content

Commit 86874b2

Browse files
committed
fix: post-audit edge case fixes + titlebar focus ring
- Sync tauri.conf.json version to 0.1.3 - Use io_error() consistently for backup persist errors - Walk up ancestors in path canonicalization for non-existent parents - Clear saveQueueRef on unmount in useAppPersistence - Remove default focus outline on titlebar buttons (keep :focus-visible) - Add .audit/ to .gitignore
1 parent 0eff98e commit 86874b2

File tree

6 files changed

+34
-16
lines changed

6 files changed

+34
-16
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,5 +41,8 @@ docs/plans/
4141
docs/research/
4242
docs/mockups/
4343

44+
# Audit reports (generated, not source)
45+
.audit/
46+
4447
# Portable build output
4548
Sidearm-Portable/

src-tauri/src/config.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -801,10 +801,7 @@ fn write_config_to_path(
801801
.map_err(|error| io_error(Some(&backup_path), error))?;
802802
backup_tmp
803803
.persist(&backup_path)
804-
.map_err(|error| ConfigStoreError::Io {
805-
path: Some(path_string(&backup_path)),
806-
message: format!("Failed to persist backup atomically: {}", error.error),
807-
})?;
804+
.map_err(|error| io_error(Some(&backup_path), error.error))?;
808805
}
809806

810807
let serialized = serde_json::to_string_pretty(config)

src-tauri/src/lib.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,9 @@ fn validate_user_file_path(path: &str) -> Result<PathBuf, CommandError> {
342342
})?;
343343

344344
// For existing paths (reads): canonicalize the path itself.
345-
// For new files (writes): canonicalize the parent directory, then append filename.
346-
// std::fs::canonicalize returns NotFound on non-existent paths, so we must
347-
// handle the write case (new file) by canonicalizing only the parent.
345+
// For new files (writes): walk up to the nearest existing ancestor, canonicalize
346+
// it, then append the non-existent tail. This handles writes where intermediate
347+
// directories don't exist yet (create_dir_all runs after validation).
348348
let canonical = if path.exists() {
349349
std::fs::canonicalize(&path).map_err(|e| {
350350
CommandError::new(
@@ -354,19 +354,30 @@ fn validate_user_file_path(path: &str) -> Result<PathBuf, CommandError> {
354354
)
355355
})?
356356
} else {
357-
let parent = path.parent().ok_or_else(|| {
358-
CommandError::new("invalid_path", "Path has no parent directory.", None)
359-
})?;
360-
let canonical_parent = std::fs::canonicalize(parent).map_err(|e| {
357+
let mut tail: Vec<std::ffi::OsString> = Vec::new();
358+
let mut cursor = path.as_path();
359+
loop {
360+
tail.push(cursor.file_name().ok_or_else(|| {
361+
CommandError::new("invalid_path", "Path has no filename component.", None)
362+
})?.to_owned());
363+
cursor = cursor.parent().ok_or_else(|| {
364+
CommandError::new("invalid_path", "No existing ancestor directory found.", None)
365+
})?;
366+
if cursor.exists() {
367+
break;
368+
}
369+
}
370+
let mut canonical = std::fs::canonicalize(cursor).map_err(|e| {
361371
CommandError::new(
362372
"invalid_path",
363-
format!("Parent canonicalization failed: {e}"),
373+
format!("Ancestor canonicalization failed: {e}"),
364374
None,
365375
)
366376
})?;
367-
canonical_parent.join(path.file_name().ok_or_else(|| {
368-
CommandError::new("invalid_path", "Path has no filename.", None)
369-
})?)
377+
for part in tail.into_iter().rev() {
378+
canonical.push(part);
379+
}
380+
canonical
370381
};
371382

372383
if !canonical.starts_with(&home) {

src-tauri/tauri.conf.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"$schema": "https://schema.tauri.app/config/2",
33
"productName": "Sidearm",
4-
"version": "0.1.2",
4+
"version": "0.1.3",
55
"identifier": "com.sidearm.desktop",
66
"build": {
77
"beforeDevCommand": "npm run dev",

src/App.css

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,12 +121,18 @@ button, input, textarea, select {
121121
width: 46px;
122122
height: 100%;
123123
border: none;
124+
outline: none;
124125
background: transparent;
125126
color: var(--c-text-muted);
126127
cursor: pointer;
127128
transition: background-color 0.12s, color 0.12s;
128129
}
129130

131+
.titlebar__btn:focus-visible {
132+
outline: 1px solid var(--c-accent);
133+
outline-offset: -1px;
134+
}
135+
130136
.titlebar__btn:hover {
131137
background: rgba(255, 255, 255, 0.08);
132138
color: var(--c-text-bright);

src/hooks/useAppPersistence.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ export function useAppPersistence(onAutoSaved?: () => void): AppPersistence {
6161
return () => {
6262
disposedRef.current = true;
6363
clearTimeout(saveTimerRef.current);
64+
saveQueueRef.current = null;
6465
};
6566
}, []);
6667

0 commit comments

Comments
 (0)