From f20bdd38a6fd742379d84e44f03ca80676dcc309 Mon Sep 17 00:00:00 2001 From: Griffen Fargo <3642037+gfargo@users.noreply.github.com> Date: Wed, 26 Aug 2026 18:53:20 -0400 Subject: [PATCH] refactor(doctor): share deploy path comparison --- lib/cmd_doctor.sh | 19 +++++++++++-------- lib/compare.sh | 31 +++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 8 deletions(-) diff --git a/lib/cmd_doctor.sh b/lib/cmd_doctor.sh index b993ca0..ff6cb67 100644 --- a/lib/cmd_doctor.sh +++ b/lib/cmd_doctor.sh @@ -10,6 +10,8 @@ set -euo pipefail +declare -F compare_path_within >/dev/null || source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/compare.sh" + # ── State ───────────────────────────────────────────────────────────────────── _DOC_PASSED=0 _DOC_WARNED=0 @@ -303,10 +305,11 @@ _doc_check_vps() { fi if [ -n "${f_working_dir:-}" ]; then - local _expected_prefix="$deploy_dir/stacks/" - if [[ "$f_working_dir" != "$_expected_prefix"* ]]; then + local _expected_root + _expected_root=$(compare_normalize_path "$deploy_dir/stacks") + if ! compare_path_within "$f_working_dir" "$_expected_root"; then _doc_warn "VPS deploy-dir ($env_name)" \ - "containers run from $f_working_dir, expected under ${_expected_prefix%/}" "" + "containers run from $f_working_dir, expected under $_expected_root" "" fi fi fi @@ -453,20 +456,20 @@ REMOTE if [[ "$workingdir_lines" == *"EMPTY"* ]] || [ -z "$workingdir_lines" ]; then _doc_pass "$label / workingdir" "no running containers (skip)" else - local expected_prefix - expected_prefix="$deploy_dir/stacks" + local expected_root + expected_root=$(compare_normalize_path "$deploy_dir/stacks") local mismatch_found=false while IFS= read -r wdir; do [ -z "$wdir" ] && continue - if [[ "$wdir" != "$expected_prefix"* ]]; then + if ! compare_path_within "$wdir" "$expected_root"; then _doc_warn "$label / workingdir" \ - "container working_dir '$wdir' outside expected prefix '$expected_prefix'" \ + "container working_dir '$wdir' outside expected prefix '$expected_root'" \ "Check VPS_DEPLOY_DIR or re-deploy from the correct checkout" mismatch_found=true fi done <<< "$workingdir_lines" if ! $mismatch_found; then - _doc_pass "$label / workingdir" "all containers under $expected_prefix" + _doc_pass "$label / workingdir" "all containers under $expected_root" fi fi } diff --git a/lib/compare.sh b/lib/compare.sh index 0bb3944..2cdbef6 100644 --- a/lib/compare.sh +++ b/lib/compare.sh @@ -62,3 +62,34 @@ compare_artifacts_equal() { local right="$3" [ "$(compare_artifact_hash "$artifact" "$left")" = "$(compare_artifact_hash "$artifact" "$right")" ] } + +# compare_normalize_path +# Normalizes separators without resolving filesystem components. Remote runtime +# paths may not exist locally, so `realpath` is intentionally inappropriate. +compare_normalize_path() { + local path="$1" + [ -n "$path" ] || return 1 + + while [[ "$path" == *//* ]]; do + path="${path//\/\//\/}" + done + while [ "$path" != "/" ] && [[ "$path" == */ ]]; do + path="${path%/}" + done + + printf '%s' "$path" +} + +# compare_path_within +# Returns success only when candidate is a lexical descendant of intent-root. +compare_path_within() { + local candidate intent_root + candidate=$(compare_normalize_path "$1") || return 1 + intent_root=$(compare_normalize_path "$2") || return 1 + + if [ "$intent_root" = "/" ]; then + [[ "$candidate" == /* && "$candidate" != "/" ]] + else + [[ "$candidate" == "$intent_root/"* ]] + fi +}