summaryrefslogtreecommitdiff
path: root/tests/cli.sh
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-06-16 23:11:32 +0300
committerPaul Buetow <paul@buetow.org>2026-06-16 23:11:32 +0300
commitca5bcf37e40d4dbd41dc9d9d001d6f4b9c6dcd65 (patch)
tree9deb2da9693d422ea01995e216862239194b4fd7 /tests/cli.sh
parent72f72995a9c4a1ddd2ea3adb04cc2d7641410245 (diff)
8n0 validate DIST_DIR before --clean rm -rf
The --clean action ran `rm -rf "$DIST_DIR"` after only an `[ -d ]` check, so a misconfigured DIST_DIR (empty, /, $HOME, system dirs, etc.) could recursively delete the wrong tree. Add validate_clean_dist_dir (and resolve_dist_dir_path) in config.validate.source.sh and call it in the --clean case before any deletion. The guard canonicalizes DIST_DIR with `pwd -P` (handling ./ trailing slashes, symlinks and relative paths; for a not-yet-existing dir it resolves the existing parent and re-attaches the basename) and refuses to clean when the resolved path is empty, the filesystem root, a well-known system directory, the resolved $HOME, or the current working directory. Rejection uses config_error with a clear message and a non-zero exit, so nothing is deleted. Normal DIST_DIRs still clean. Tests (tests/cli.sh, registered in main): a HOME-as-DIST_DIR case (uses a fake HOME under TEST_TMPDIR with a sentinel file, so a regression can only touch the throwaway temp dir) and an empty-DIST_DIR case both assert rejection and that nothing is removed. Note: leftover staging artifacts on --clean are out of scope (task ln0). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Diffstat (limited to 'tests/cli.sh')
-rwxr-xr-xtests/cli.sh52
1 files changed, 52 insertions, 0 deletions
diff --git a/tests/cli.sh b/tests/cli.sh
index 705ee52..859d104 100755
--- a/tests/cli.sh
+++ b/tests/cli.sh
@@ -305,6 +305,54 @@ test_clean_cli_dist_overrides_config() {
test::teardown
}
+# --clean must refuse to delete a DIST_DIR that resolves to a dangerous path
+# (here: the user's HOME). We point HOME at a directory we fully control under
+# TEST_TMPDIR and seed it with a sentinel file, so a regression can only "delete"
+# our throwaway temp dir -- never a real HOME -- and we assert nothing was
+# removed and the command failed with a clear error.
+test_clean_rejects_dangerous_dist_dir() {
+ local config_file
+ local fake_home
+ local output
+
+ test::setup
+ fake_home="$TEST_TMPDIR/fake-home"
+ mkdir -p "$fake_home"
+ touch "$fake_home/sentinel"
+ config_file="$TEST_TMPDIR/shuriken.conf"
+ printf 'DIST_DIR=%q\n' "$fake_home" > "$config_file"
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ HOME="$fake_home" \
+ test::capture_failure_output "$TEST_SHURIKEN" --clean
+ )
+
+ test::assert_contains 'refusing to clean DIST_DIR' "$output"
+ test::assert_contains 'is HOME' "$output"
+ test::assert_dir_exists "$fake_home"
+ test::assert_file_exists "$fake_home/sentinel"
+ test::teardown
+}
+
+# --clean must also refuse an empty DIST_DIR (which would otherwise rm -rf "").
+test_clean_rejects_empty_dist_dir() {
+ local config_file
+ local output
+
+ test::setup
+ config_file="$TEST_TMPDIR/shuriken.conf"
+ printf "DIST_DIR=''\n" > "$config_file"
+
+ output=$(
+ cd "$TEST_TMPDIR"
+ test::capture_failure_output "$TEST_SHURIKEN" --clean
+ )
+
+ test::assert_contains 'DIST_DIR must be set' "$output"
+ test::teardown
+}
+
test_missing_config_fails_without_legacy_fallbacks() {
local default_rc
local home_dir
@@ -5685,6 +5733,10 @@ main() {
test::run_case '--clean --config succeeds' test_clean_with_config
test::run_case '--clean --dist overrides config' \
test_clean_cli_dist_overrides_config
+ test::run_case '--clean rejects dangerous DIST_DIR' \
+ test_clean_rejects_dangerous_dist_dir
+ test::run_case '--clean rejects empty DIST_DIR' \
+ test_clean_rejects_empty_dist_dir
test::run_case \
'missing config ignores legacy fallbacks' \
test_missing_config_fails_without_legacy_fallbacks