diff --git a/crates/bashkit/src/interpreter/mod.rs b/crates/bashkit/src/interpreter/mod.rs index a96d8f41..2d3dc7bc 100644 --- a/crates/bashkit/src/interpreter/mod.rs +++ b/crates/bashkit/src/interpreter/mod.rs @@ -4151,8 +4151,9 @@ impl Interpreter { } if let Ok(content) = self.fs.read_file(&candidate).await { let script_text = bytes_to_latin1_string(&content); + let resolved = candidate.to_string_lossy(); let result = self - .execute_script_content(name, &script_text, args, stdin, redirects) + .execute_script_content(&resolved, &script_text, args, stdin, redirects) .await?; return Ok(Some(result)); } diff --git a/crates/bashkit/tests/bash_source_tests.rs b/crates/bashkit/tests/bash_source_tests.rs index ae3eb51a..c2580e0a 100644 --- a/crates/bashkit/tests/bash_source_tests.rs +++ b/crates/bashkit/tests/bash_source_tests.rs @@ -50,6 +50,54 @@ async fn bash_source_guard_direct_execution() { assert_eq!(result.stdout.trim(), "direct"); } +/// BASH_SOURCE[0] is set to the resolved path when script is executed via PATH lookup +#[tokio::test] +async fn bash_source_set_via_path_lookup() { + let mut bash = Bash::new(); + let fs = bash.fs(); + + // Create a script in /scripts + fs.mkdir(Path::new("/scripts"), false).await.unwrap(); + fs.write_file( + Path::new("/scripts/test.sh"), + b"#!/bin/bash\necho \"source=${BASH_SOURCE[0]}\"", + ) + .await + .unwrap(); + fs.chmod(Path::new("/scripts/test.sh"), 0o755) + .await + .unwrap(); + + // Add /scripts to PATH and run by name + let result = bash + .exec("export PATH=\"/scripts:${PATH}\"\ntest.sh") + .await + .unwrap(); + assert_eq!(result.stdout.trim(), "source=/scripts/test.sh"); +} + +/// Source guard pattern works correctly when script is executed via PATH lookup +#[tokio::test] +async fn bash_source_guard_via_path_lookup() { + let mut bash = Bash::new(); + let fs = bash.fs(); + + fs.mkdir(Path::new("/bin2"), false).await.unwrap(); + fs.write_file( + Path::new("/bin2/guard.sh"), + b"#!/bin/bash\nif [[ \"${BASH_SOURCE[0]}\" == \"$0\" ]]; then echo direct; else echo sourced; fi", + ) + .await + .unwrap(); + fs.chmod(Path::new("/bin2/guard.sh"), 0o755).await.unwrap(); + + let result = bash + .exec("export PATH=\"/bin2:${PATH}\"\nguard.sh") + .await + .unwrap(); + assert_eq!(result.stdout.trim(), "direct"); +} + /// Source guard pattern: BASH_SOURCE[0] != $0 when sourced #[tokio::test] async fn bash_source_guard_sourced() {