Skip to content

guard shell setup snippets against non-interactive logins - #1553

Open
ChrisJr404 wants to merge 1 commit into
Schniz:masterfrom
ChrisJr404:fix-readme-interactive-shell-guard
Open

guard shell setup snippets against non-interactive logins#1553
ChrisJr404 wants to merge 1 commit into
Schniz:masterfrom
ChrisJr404:fix-readme-interactive-shell-guard

Conversation

@ChrisJr404

Copy link
Copy Markdown

Closes #1551.

Why

The setup snippets we publish (and the ones the installer appends to user dotfiles) run fnm env unconditionally:

eval "$(fnm env --use-on-cd --shell bash)"

On Linux with a systemd user session, the display manager spawns a non-interactive login shell at session start to scrape env vars. With Plasma/SDDM the call tree is:

plasmalogin
 `-wayland-session
     `-fish --login -c /bin/sh -c 'export -p' > /tmp/xsess-env-...
         `- fnm env runs here, multishell is created, and systemd freezes it
            into the global session PATH

After that, every interactive terminal inherits the stale fnm_multishells/<dir> from the session env and adds its own on top. The visible symptom: fnm use system resolves to the older session-level multishell instead of /usr/bin/node. Detailed repro and pstree capture are in the linked issue.

Fix

Wrap the documented invocations and the installer-appended snippets in an interactive-shell check, so non-interactive parents leave PATH untouched:

bash and zsh

[[ $- == *i* ]] && eval "$(fnm env --use-on-cd --shell bash)"

fish

status is-interactive; and fnm env --use-on-cd --shell fish | source

Same check is added inside the existing if [ -d "$FNM_PATH" ] block in .ci/install.sh for bash, zsh and fish.

PowerShell and the WinCMD/Cmder snippets are left alone since the issue is specific to Linux display-manager session-init behavior, and adding an untested PowerShell host-interactive check has more downside than upside here.

Testing

Verified each guard locally against an actual non-interactive vs interactive invocation:

$ bash -c 'case $- in *i*) echo INTERACTIVE ;; *) echo NOT ;; esac'
NOT
$ bash -i -c 'case $- in *i*) echo INTERACTIVE ;; *) echo NOT ;; esac'
INTERACTIVE

$ zsh -c    '[[ $- == *i* ]] && echo INTERACTIVE || echo NOT'
NOT
$ zsh -i -c '[[ $- == *i* ]] && echo INTERACTIVE || echo NOT'
INTERACTIVE

$ fish    -c 'status is-interactive; and echo INTERACTIVE; or echo NOT'
NOT
$ fish -i -c 'status is-interactive; and echo INTERACTIVE; or echo NOT'
INTERACTIVE

bash -n, zsh -n and fish -n all parse the generated snippets cleanly.

.ci/test_installation_script.sh now runs the test shells with -i -c so the appended fnm block actually fires through the guard when sourcing the profile. Without that change the existing CI path (bash, zsh, fish all invoked as -c) would no-op the eval and the fnm install / fnm use steps would fail to find node on PATH.

A changeset (patch) is included.

The README setup snippets and the installer-appended ones for bash, zsh and
fish run `fnm env` unconditionally. Non-interactive logins (notably KDE/SDDM
running `fish --login -c '/bin/sh -c export -p'` to scrape env vars at session
start) hit that snippet too, which generates a multishell directory and ends
up baked into the systemd user environment. Every subsequent terminal then
runs `fnm env` on top of that stale path, and `fnm use system` resolves to
the old multishell instead of /usr/bin/node.

Wrap the documented and installer-emitted invocations in an interactive
check so the non-interactive path is a no-op:

  bash/zsh: [[ $- == *i* ]] && eval ...
  fish:     status is-interactive; and fnm env ... | source

The installer-side CI test now invokes the test shells with `-i` so the
sourced profile still initializes fnm under the guard.

Closes Schniz#1551

Signed-off-by: ChrisJr404 <chris@hacknow.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: fnm env setup scripts lack interactive shell guard, causing stacked multishells on KDE/systemd

1 participant