diff --git a/acq.backends/common.sh b/acq.backends/common.sh index 008a1d7..9d3223e 100644 --- a/acq.backends/common.sh +++ b/acq.backends/common.sh @@ -1185,10 +1185,11 @@ acq_guest_shell_script() { # # Emitted lines are evaluated by the guest login shell. They gate to bash, # list snippets with C collation for deterministic order, preserve the readable -# and charset guards, and clean up the loop variable after sourcing. +# and charset guards, and clean up the loop variable after sourcing. `command ls` +# because ~/.profile sources ~/.bashrc first, which may alias or wrap ls. acq_login_profile_rc_block() { printf '%s\n' 'if [ -n "$BASH_VERSION" ] && [ -d "$HOME/.rc.d" ]; then' - printf '%s\n' ' for _acq_rc in $(LC_ALL=C ls "$HOME"/.rc.d 2>/dev/null); do' + printf '%s\n' ' for _acq_rc in $(LC_ALL=C command ls "$HOME"/.rc.d 2>/dev/null); do' printf '%s\n' ' _acq_rc="$HOME/.rc.d/$_acq_rc"' printf '%s\n' ' case "$_acq_rc" in *.sh) ;; *) continue ;; esac' printf '%s\n' ' [ -r "$_acq_rc" ] || continue' diff --git a/test/bats/72-msb-agent-user.bats b/test/bats/72-msb-agent-user.bats index 757f487..9cb90b5 100644 --- a/test/bats/72-msb-agent-user.bats +++ b/test/bats/72-msb-agent-user.bats @@ -314,9 +314,9 @@ _attach() { # PRE_SNIPPET NAME _provision rcdbox shell 'export ACQ_SECRET_STORE_DIR="'"$STUBDIR"'/rcd-secrets"' local log; log=$(cat "$CALLS") # The bridge sources ~/.rc.d in deterministic C-collation order (ADR-0030): - # it must iterate an `LC_ALL=C ls "$HOME"/.rc.d` list, NOT a bare locale- + # it must iterate an `LC_ALL=C command ls "$HOME"/.rc.d` list, NOT a bare locale- # dependent `*.sh` glob whose order can vary by guest locale. - assert_regex "$log" 'LC_ALL=C ls' + assert_regex "$log" 'LC_ALL=C command ls' assert_regex "$log" '\$HOME./.rc.d' assert_regex "$log" 'for _acq_rc in' assert_regex "$log" 'SC1090' @@ -340,6 +340,29 @@ _attach() { # PRE_SNIPPET NAME assert_output $'10-a\n2-b' } +@test "rc.d: login-profile block ignores an ls alias or function from .bashrc (#587)" { + # The bridge runs after ~/.profile sources ~/.bashrc, so an interactive + # login shell already has the user's `ls` alias or function when the block + # lists ~/.rc.d. The listing must come from the real ls. + local home="$STUBDIR/rc-alias-home" + mkdir -p "$home/.rc.d" + printf '%s\n' 'printf "%s\n" 10-a >> "$HOME/order"' > "$home/.rc.d/10-a.sh" + printf '%s\n' 'printf "%s\n" 20-b >> "$HOME/order"' > "$home/.rc.d/20-b.sh" + acq_login_profile_rc_block > "$home/profile" + + # An alias that reverses the order. + run env HOME="$home" bash -c 'shopt -s expand_aliases; alias ls="ls -r" +. "$HOME/profile"; cat "$HOME/order"' + assert_success + assert_output $'10-a\n20-b' + + # A function whose output names one snippet twice and omits the other. + rm -f "$home/order" + run env HOME="$home" bash -c 'ls() { echo 20-b.sh 20-b.sh; }; . "$HOME/profile"; cat "$HOME/order"' + assert_success + assert_output $'10-a\n20-b' +} + @test "msb #426: the heal only rewrites a .profile acq owns outright (appended lines survive)" { # Tools like rustup append to ~/.profile below acq's bridge. The rewrite # condition must be marker-present AND still just the bridge (line-count diff --git a/test/bats/90-sbx-startup-kit.bats b/test/bats/90-sbx-startup-kit.bats index b10342c..12da072 100644 --- a/test/bats/90-sbx-startup-kit.bats +++ b/test/bats/90-sbx-startup-kit.bats @@ -239,8 +239,8 @@ SPEC local log; log=$(cat "$CALLS") # The bridge is written via a post-create `sbx exec` (not a startup kit). assert_regex "$log" 'acq-login-profile-rc' - # Deterministic lexical order: an LC_ALL=C ls list, NOT a locale-dependent glob. - assert_regex "$log" 'LC_ALL=C ls' + # Deterministic lexical order: an LC_ALL=C command ls list, NOT a locale-dependent glob. + assert_regex "$log" 'LC_ALL=C command ls' assert_regex "$log" 'for _acq_rc in' assert_regex "$log" 'SC1090' assert_regex "$log" 'unset _acq_rc'