diff --git a/Cargo.lock b/Cargo.lock index 380393ee..c04029ce 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3868,6 +3868,7 @@ dependencies = [ "serde_json", "sha-1", "sha2 0.10.9", + "shlex", "tar", "techscript_runtime", "tiny_http", diff --git a/stdlib/Cargo.toml b/stdlib/Cargo.toml index 807e727c..9a7a0395 100644 --- a/stdlib/Cargo.toml +++ b/stdlib/Cargo.toml @@ -36,3 +36,4 @@ uuid = { version = "1", features = ["v4"] } rustls = { version = "0.23", optional = true } tokio = { version = "1", features = ["rt", "macros", "sync", "time"], optional = true } hex = "0.4.3" +shlex = "2.0.1" diff --git a/stdlib/src/process.rs b/stdlib/src/process.rs index fb9a27fc..4626dac6 100644 --- a/stdlib/src/process.rs +++ b/stdlib/src/process.rs @@ -114,8 +114,25 @@ impl StdlibRegistry { )) } }; - Command::new("cmd") - .args(["/C", &cmd]) + + let parsed = shlex::split(&cmd).ok_or_else(|| { + RuntimeError::new( + RuntimeErrorKind::InvalidOperation("Failed to parse command string".to_string()), + None, + None, + ) + })?; + + if parsed.is_empty() { + return Err(RuntimeError::new( + RuntimeErrorKind::InvalidOperation("Empty command string".to_string()), + None, + None, + )); + } + + Command::new(&parsed[0]) + .args(&parsed[1..]) .spawn() .map_err(|e| { RuntimeError::new( diff --git a/stdlib/tests/stdlib_tests.rs b/stdlib/tests/stdlib_tests.rs index a86d759d..edf703dc 100644 --- a/stdlib/tests/stdlib_tests.rs +++ b/stdlib/tests/stdlib_tests.rs @@ -1,7 +1,7 @@ use std::cell::RefCell; use std::collections::HashSet; use std::rc::Rc; -use techscript_runtime::{context::Capability, value::RuntimeValue, RuntimeConfig, RuntimeContext}; +use techscript_runtime::{context::Capability, value::RuntimeValue, RuntimeConfig, RuntimeContext, error::RuntimeErrorKind}; use techscript_stdlib::StdlibRegistry; #[test]