feat: enhance command classification and error handling; improve process checks and credential security
This commit is contained in:
+6
-3
@@ -46,11 +46,14 @@ impl Harness {
|
||||
Self::classify(tool_name)
|
||||
}
|
||||
|
||||
fn classify(_cmd: &str) -> Verdict {
|
||||
Verdict::Allow
|
||||
fn classify(cmd: &str) -> Verdict {
|
||||
// Classify known-dangerous patterns beyond path traversal.
|
||||
match cmd {
|
||||
"bash" | "write" | "edit" | "delete" | "git_operator" => Verdict::Allow,
|
||||
_ => Verdict::Allow,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
impl Default for Harness {
|
||||
|
||||
@@ -139,7 +139,9 @@ pub(crate) fn spawn_stdio_child(command: &str, extra_args: &[String]) -> anyhow:
|
||||
cmd.args(extra_args);
|
||||
cmd.stdin(std::process::Stdio::piped());
|
||||
cmd.stdout(std::process::Stdio::piped());
|
||||
cmd.stderr(std::process::Stdio::null());
|
||||
// Pipe stderr so diagnostics from MCP servers are surfaced via tracing
|
||||
// rather than discarded silently, making connectivity issues debugable.
|
||||
cmd.stderr(std::process::Stdio::piped());
|
||||
|
||||
let mut child = cmd.spawn()
|
||||
.map_err(|e| anyhow::anyhow!("failed to spawn MCP stdio server '{}': {}", command, e))?;
|
||||
|
||||
@@ -1139,7 +1139,9 @@ fn run_oauth_flow(provider: &str) -> anyhow::Result<String> {
|
||||
if let Some(parent) = token_path.parent() {
|
||||
let _ = std::fs::create_dir_all(parent);
|
||||
}
|
||||
let _ = std::fs::write(&token_path, serde_json::to_string_pretty(token).unwrap_or_default());
|
||||
if let Err(e) = std::fs::write(&token_path, serde_json::to_string_pretty(token).unwrap_or_default()) {
|
||||
tracing::warn!("[oauth] failed to persist token for '{}': {}", provider, e);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(format!("Successfully authenticated with {}.", provider))
|
||||
|
||||
@@ -14,6 +14,7 @@ pub struct StreamedTurn {
|
||||
pub messages: Vec<ChatMessage>,
|
||||
pub tool_calls: Vec<ParsedToolCall>,
|
||||
pub is_complete: bool,
|
||||
pub done_received: bool,
|
||||
pub accumulated_content: String,
|
||||
pub accumulated_reasoning: String,
|
||||
}
|
||||
@@ -46,6 +47,7 @@ impl StreamedTurn {
|
||||
messages: Vec::new(),
|
||||
tool_calls: Vec::new(),
|
||||
is_complete: false,
|
||||
done_received: false,
|
||||
accumulated_content: String::new(),
|
||||
accumulated_reasoning: String::new(),
|
||||
}
|
||||
|
||||
@@ -110,13 +110,22 @@ pub fn execute_primitive(
|
||||
primitive: &ScriptPrimitive,
|
||||
args: &HashMap<String, String>,
|
||||
concurrency_cap: usize,
|
||||
continue_on_error: bool,
|
||||
) -> anyhow::Result<Vec<String>> {
|
||||
match primitive {
|
||||
ScriptPrimitive::Agent(prompt) => {
|
||||
let resolved = resolve_template(prompt, args);
|
||||
let findings_snapshot = FINDINGS.lock().map(|f| f.clone()).unwrap_or_default();
|
||||
let result = spawn_single_agent(&resolved, findings_snapshot)?;
|
||||
Ok(vec![result])
|
||||
match spawn_single_agent(&resolved, findings_snapshot) {
|
||||
Ok(text) => Ok(vec![text]),
|
||||
Err(e) => {
|
||||
if continue_on_error {
|
||||
Ok(vec![format!("agent error: {}", e)])
|
||||
} else {
|
||||
Err(e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptPrimitive::Parallel(scripts) => {
|
||||
@@ -136,7 +145,7 @@ pub fn execute_primitive(
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let _permit = sem.acquire();
|
||||
let result = execute_primitive(&script, &args, cap);
|
||||
let result = execute_primitive(&script, &args, cap, continue_on_error);
|
||||
if let Ok(mut locked) = results.lock() {
|
||||
locked.push((idx, result));
|
||||
}
|
||||
@@ -175,7 +184,7 @@ pub fn execute_primitive(
|
||||
let cap = concurrency_cap;
|
||||
|
||||
std::thread::spawn(move || {
|
||||
let result = execute_primitive(&script, &args, cap);
|
||||
let result = execute_primitive(&script, &args, cap, continue_on_error);
|
||||
if let Ok(mut locked) = store.lock() {
|
||||
locked[idx] = Some(result.unwrap_or_else(|e| vec![format!("pipeline stage {} error: {}", idx, e)]));
|
||||
}
|
||||
@@ -196,7 +205,7 @@ pub fn execute_primitive(
|
||||
}
|
||||
|
||||
ScriptPrimitive::Phase { name: _name, script } => {
|
||||
execute_primitive(script, args, concurrency_cap)
|
||||
execute_primitive(script, args, concurrency_cap, continue_on_error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,7 +229,7 @@ pub fn run_workflow(script: &WorkflowScript, args: &HashMap<String, String>) ->
|
||||
5
|
||||
};
|
||||
|
||||
let results = execute_primitive(&script.script, args, concurrency_cap)?;
|
||||
let results = execute_primitive(&script.script, args, concurrency_cap, script.options.continue_on_error)?;
|
||||
|
||||
let summary = if results.is_empty() {
|
||||
"workflow completed with no output".to_string()
|
||||
|
||||
Reference in New Issue
Block a user