feat: enhance safety and crash resilience in file operations; add fsync to critical writes and checks for path traversal
This commit is contained in:
@@ -36,13 +36,16 @@ pub fn load_global_agents() -> Vec<AgentDefinition> {
|
||||
agents
|
||||
}
|
||||
|
||||
/// Persist a global agent definition as `<store>/agents/<name>.json`.
|
||||
/// Persist a global agent definition as `<store>/agents/<name>.json`,
|
||||
/// with fsync for crash safety.
|
||||
///
|
||||
/// Flow: ensure the `agents/` directory exists → serialize `def` to
|
||||
/// pretty JSON → write to a file named after `def.name`.
|
||||
/// pretty JSON → write to a temp file → fsync → rename into place →
|
||||
/// fsync parent directory.
|
||||
///
|
||||
/// Why: writing by name overwrites any existing definition with the
|
||||
/// same name, acting as an upsert.
|
||||
/// same name, acting as an upsert; fsync prevents a torn write from
|
||||
/// losing the definition on crash.
|
||||
///
|
||||
/// Return: `Ok(())` on success, or an error if directory creation,
|
||||
/// serialization, or the write fails.
|
||||
@@ -51,8 +54,13 @@ pub fn save_global_agent(def: &AgentDefinition) -> anyhow::Result<()> {
|
||||
let agents_dir = store.base_dir.join("agents");
|
||||
std::fs::create_dir_all(&agents_dir)?;
|
||||
let path = agents_dir.join(format!("{}.json", def.name));
|
||||
let tmp = agents_dir.join(format!("{}.json.tmp", def.name));
|
||||
let content = serde_json::to_string_pretty(def)?;
|
||||
std::fs::write(path, content)?;
|
||||
std::fs::write(&tmp, content)?;
|
||||
let f = std::fs::File::open(&tmp)?;
|
||||
f.sync_all()?;
|
||||
std::fs::rename(&tmp, path)?;
|
||||
let _ = std::fs::File::open(&agents_dir).and_then(|d| d.sync_all());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -31,17 +31,23 @@ pub fn load_session_agents(session_dir: &Path) -> Vec<AgentDefinition> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Overwrite `<session_dir>/agents.json` with the given agent list.
|
||||
/// Overwrite `<session_dir>/agents.json` with the given agent list,
|
||||
/// with fsync for crash safety.
|
||||
///
|
||||
/// Flow: serialize `agents` to pretty JSON → write to
|
||||
/// `<session_dir>/agents.json`.
|
||||
/// Flow: serialize `agents` to pretty JSON → write to a temp file →
|
||||
/// fsync → rename over `agents.json` → fsync parent directory.
|
||||
///
|
||||
/// Return: `Ok(())` on success, or an error if serialization or the
|
||||
/// write fails.
|
||||
pub fn save_session_agents(session_dir: &Path, agents: &[AgentDefinition]) -> anyhow::Result<()> {
|
||||
let agents_file = session_dir.join("agents.json");
|
||||
let tmp = session_dir.join("agents.json.tmp");
|
||||
let content = serde_json::to_string_pretty(agents)?;
|
||||
std::fs::write(agents_file, content)?;
|
||||
std::fs::write(&tmp, content)?;
|
||||
let f = std::fs::File::open(&tmp)?;
|
||||
f.sync_all()?;
|
||||
std::fs::rename(&tmp, agents_file)?;
|
||||
let _ = std::fs::File::open(session_dir).and_then(|d| d.sync_all());
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user