summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib/action.source.sh10
-rw-r--r--src/lib/config.validate.source.sh84
2 files changed, 94 insertions, 0 deletions
diff --git a/src/lib/action.source.sh b/src/lib/action.source.sh
index 12be053..edececa 100644
--- a/src/lib/action.source.sh
+++ b/src/lib/action.source.sh
@@ -188,6 +188,16 @@ run_configured_action() {
case "$SHURIKEN_CLI_ACTION" in
--clean)
+ # Validate DIST_DIR before any destructive rm -rf. Unlike the bare
+ # check that used to live here, validate_clean_dist_dir rejects unset,
+ # empty, and dangerous paths (/, HOME, cwd, system dirs) so a
+ # misconfigured DIST_DIR can never nuke the wrong tree.
+ validate_clean_dist_dir
+ status=$?
+ if (( status != 0 )); then
+ return "$status"
+ fi
+
if [ -d "$DIST_DIR" ]; then
log_info "Cleaning $DIST_DIR"
rm -rf "$DIST_DIR"
diff --git a/src/lib/config.validate.source.sh b/src/lib/config.validate.source.sh
index 7519094..28aeace 100644
--- a/src/lib/config.validate.source.sh
+++ b/src/lib/config.validate.source.sh
@@ -74,6 +74,90 @@ validate_dist_dir() {
fi
}
+# Resolve DIST_DIR to a canonical absolute path so the --clean guard cannot be
+# bypassed via "." / trailing slashes / symlinks / relative paths. The directory
+# itself may not exist yet (cleaning a stale config), so when it is missing we
+# resolve its existing parent and append the basename. Output is printed; the
+# caller captures it. Returns non-zero only if even the parent cannot resolve.
+resolve_dist_dir_path() {
+ local -r target_dir="$1"; shift
+ local parent base
+
+ if [ -d "$target_dir" ]; then
+ ( cd "$target_dir" && pwd -P ) && return
+ return 1
+ fi
+
+ # DIST_DIR does not exist: canonicalize the deepest existing ancestor and
+ # re-attach the remaining path so symlinked parents are still resolved.
+ parent=$(existing_parent_dir "$target_dir")
+ base=${target_dir#"$parent"}
+ base=${base#/}
+ parent=$( cd "$parent" && pwd -P ) || return 1
+ if [ -n "$base" ]; then
+ printf '%s/%s\n' "$parent" "$base"
+ else
+ printf '%s\n' "$parent"
+ fi
+}
+
+# Guard for the destructive --clean action: refuse to "rm -rf" DIST_DIR when it
+# resolves to an empty value or a clearly dangerous location (filesystem root,
+# the user's HOME, the current working directory, or a well-known system tree).
+# This is the single place where the dangerous-path policy lives so it stays in
+# sync. NOTE (ln0): this only guards against deleting the wrong tree; leftover
+# staging artifacts are a separate concern handled by task ln0.
+validate_clean_dist_dir() {
+ local resolved home_resolved cwd_resolved
+ local -a forbidden=(
+ / /home /root /tmp /usr /etc /var /bin /sbin /lib /boot /opt
+ )
+ local entry
+
+ require_config_var DIST_DIR || return
+
+ # Reuse the shared DIST_DIR sanity checks (must be a directory, writable,
+ # parent writable) before applying the destructive-path policy.
+ validate_dist_dir || return
+
+ resolved=$(resolve_dist_dir_path "$DIST_DIR") || {
+ config_error "DIST_DIR $DIST_DIR could not be resolved"
+ return 1
+ }
+
+ if [ -z "$resolved" ]; then
+ config_error 'refusing to clean an empty DIST_DIR'
+ return 1
+ fi
+
+ # Reject the filesystem root and well-known system directories outright.
+ for entry in "${forbidden[@]}"; do
+ if [ "$resolved" = "$entry" ]; then
+ config_error \
+ "refusing to clean DIST_DIR $resolved (dangerous path)"
+ return 1
+ fi
+ done
+
+ # Reject HOME and the current working directory themselves (deleting either
+ # would be catastrophic and is never the intended DIST_DIR).
+ if [ -n "${HOME:-}" ]; then
+ home_resolved=$( cd "$HOME" 2>/dev/null && pwd -P ) || home_resolved=''
+ if [ -n "$home_resolved" ] && [ "$resolved" = "$home_resolved" ]; then
+ config_error \
+ "refusing to clean DIST_DIR $resolved (is HOME)"
+ return 1
+ fi
+ fi
+
+ cwd_resolved=$(pwd -P)
+ if [ "$resolved" = "$cwd_resolved" ]; then
+ config_error \
+ "refusing to clean DIST_DIR $resolved (is current directory)"
+ return 1
+ fi
+}
+
validate_template_dir_access() {
if [[ ! -d "$TEMPLATE_DIR" || ! -r "$TEMPLATE_DIR" \
|| ! -x "$TEMPLATE_DIR" ]]; then