From b44cdde1c1cf3871092653ea56ac18b09a5dc6e2 Mon Sep 17 00:00:00 2001 From: Chemaclass Date: Fri, 14 Aug 2026 19:27:34 +0200 Subject: [PATCH] test(sandbox): pin the two documented boundaries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --sandbox had 9 tests and none for either boundary the docs draw. A child process cannot resolve an unmocked command: `sh -c 'command -v probe'` returns empty, so the command is unreachable rather than merely unreported. That is what makes `sh -c 'curl …'` useless as an escape off Windows. An absolute path does bypass the sandbox, which is documented, and nothing kept it a deliberate boundary. The mechanism is not what it looks like. Removing `export PATH` from sandbox.sh changes nothing -- PATH is exported already, so that mutation is a no-op. The property holds because the sandbox *replaces* PATH rather than prepending to it; mutating it to "$_BASHUNIT_SANDBOX_DIR:$PATH" fails the child-process test and nothing else. Both facts are in the comment, because a comment naming the wrong dependency is worse than none. Closes #1260 --- tests/acceptance/bashunit_sandbox_test.sh | 28 +++++++++++++++++++ .../fixtures/test_bashunit_sandbox.sh | 16 +++++++++++ 2 files changed, 44 insertions(+) diff --git a/tests/acceptance/bashunit_sandbox_test.sh b/tests/acceptance/bashunit_sandbox_test.sh index 407e8e37..4002ad3b 100644 --- a/tests/acceptance/bashunit_sandbox_test.sh +++ b/tests/acceptance/bashunit_sandbox_test.sh @@ -102,3 +102,31 @@ function test_an_invalid_sandbox_allow_value_is_rejected() { assert_general_error "" "" "$ec" assert_contains "invalid --sandbox-allow value" "$output" } + +# A child process inherits the narrowed PATH, so an unmocked command is not +# merely unreported there -- it is unresolvable. That is what makes +# `sh -c 'curl …'` useless as an escape off Windows. +# +# It holds because the sandbox *replaces* PATH rather than prepending to it. +# Verified by mutation: prepending the sandbox dir instead fails this test and +# nothing else. (Dropping the `export` does not -- PATH is exported already.) +function test_a_child_process_cannot_resolve_an_unmocked_command() { + local output + output=$(run_fixture "--sandbox" "test_sandbox_child_process_cannot_resolve_the_command") + + assert_contains "1 passed" "$output" + # `command -v` printed nothing: the child could not find it. + assert_empty "$(cat "$PROBE_LOG")" +} + +# The documented limitation. Pinned so it stays a deliberate boundary: an +# absolute path bypasses PATH, so the sandbox cannot see it. +function test_an_absolute_path_bypasses_the_sandbox_as_documented() { + local output + SANDBOX_PROBE_ABS="$PROBE_DIR/bashunit_sandbox_probe" + export SANDBOX_PROBE_ABS + output=$(run_fixture "--sandbox" "test_sandbox_absolute_path_is_not_blocked") + + assert_contains "1 passed" "$output" + assert_contains "the real command ran" "$(cat "$PROBE_LOG")" +} diff --git a/tests/acceptance/fixtures/test_bashunit_sandbox.sh b/tests/acceptance/fixtures/test_bashunit_sandbox.sh index 5ee48a4b..d86e0cd7 100644 --- a/tests/acceptance/fixtures/test_bashunit_sandbox.sh +++ b/tests/acceptance/fixtures/test_bashunit_sandbox.sh @@ -32,3 +32,19 @@ function test_sandbox_after_unmock_the_command_is_blocked_again() { bashunit_sandbox_probe >"${SANDBOX_PROBE_LOG:?log required}" 2>/dev/null assert_same "ok" "ok" } + +# The boundary the docs draw. A child process inherits the narrowed PATH, so it +# cannot resolve the command at all -- that is what makes `sh -c 'curl …'` +# useless as an escape on Linux and macOS. It holds because the sandbox replaces +# PATH rather than prepending to it. +function test_sandbox_child_process_cannot_resolve_the_command() { + sh -c 'command -v bashunit_sandbox_probe' >"${SANDBOX_PROBE_LOG:?log required}" 2>/dev/null + assert_same "ok" "ok" +} + +# The documented limitation, pinned so it stays a known boundary rather than a +# surprise: an absolute path skips PATH entirely and is not blocked. +function test_sandbox_absolute_path_is_not_blocked() { + "${SANDBOX_PROBE_ABS:?abs path required}" >"${SANDBOX_PROBE_LOG:?log required}" 2>/dev/null + assert_same "ok" "ok" +}