jetify-com / devbox

Instant, easy, and predictable development environments
https://www.jetify.com/devbox/
Apache License 2.0
8.83k stars 208 forks source link

Shell initialization hooks failing when using devbox global packages with host shell #2344

Open rbhanot4739 opened 1 month ago

rbhanot4739 commented 1 month ago

What happened?

I installed devbox as per the documentation and then added few global packages. After that when I ran devbox global list I was getting the following warning

Warning: devbox global is not activated.

Add the following line to your shell's rcfile (e.g., ~/.bashrc or ~/.zshrc)
and restart your shell to fix this:

        eval "$(devbox global shellenv)"

So following the docs mentioned here I added the shell initialization hooks to to the shell rc file with eval "$(devbox global shellenv --init-hook)", but even then I am getting the following errors:

Bash

-bash: export: `BASH_FUNC_pathappend%%=() {  pathremove $1 $2; local PATHVARIABLE=${2:-PATH}; export $PATHVARIABLE="${!PATHVARIABLE:+${!PATHVARIABLE}:}$1"}': not a valid identifier
-bash: export: `BASH_FUNC_pathprepend%%=() {  pathremove $1 $2; local PATHVARIABLE=${2:-PATH}; export $PATHVARIABLE="$1${!PATHVARIABLE:+:${!PATHVARIABLE}}"}': not a valid identifier
-bash: export: `BASH_FUNC_pathremove%%=() {  local IFS=':'; local NEWPATH; local DIR; local PATHVARIABLE=${2:-PATH}; for DIR in ${!PATHVARIABLE}; do if [ "$DIR" != "$1" ]; then NEWPATH=${NEWPATH:+$NEWPATH:}$DIR; fi; done; export $PATHVARIABLE="$NEWPATH"}': not a valid identifier

Zsh

(eval):export:1: not valid in this context: BASH_FUNC_pathappend%%
/home/rbhanot/.zshrc:140: command not found: fzf
/home/rbhanot/.zshrc:142: command not found: zoxide

Even after adding the devbox initialization hook to zshrc/bashrc devbox not seem to be activated, and the installed packages are not added to the path, and hence all the tools which I installed via DevBox aren't being loaded(e.g. fzf and zoxide in this case). Also there is subtle discrepancy with the hook command as well as reported by the tool (eval "$(devbox global shellenv)") vs command in the documentation (eval "$(devbox global shellenv --init-hook)") and I have tried both but no luck.

Here is the snippet from .zshrc

eval "$(devbox global shellenv --init-hook)"
source <(fzf --zsh)
eval "$(zoxide init zsh)"

Also I am not sure why I keep getting this annoying warning after I install any package

Warning: Your devbox environment may be out of date. Run `refresh-global` or `eval "$(devbox global shellenv --preserve-path-stack -r)" && hash -r` to update it

Steps to reproduce

  1. Install devbox.
  2. Add some global packages
  3. Add the devbox initialization hook to zshrc/bashrc.

Command

shellenv

devbox.json

{
  "$schema": "https://raw.githubusercontent.com/jetify-com/devbox/0.13.4/.schema/devbox.schema.json",
  "packages": [
    "neovim@latest",
    "ripgrep@latest",
    "fzf@latest",
    "fd@latest",
    "lazygit@latest",
    "zoxide@latest",
    "eza@latest",
    "delta@latest",
    "bat@latest",
    "tealdeer@latest",
    "tmux@latest",
    "tmuxinator@latest",
    "direnv@latest",
    "jq@latest",
    "yq@latest",
    "sqlite@latest",
    "lua@latest",
    "luajit@latest",
    "luarocks@latest"
  ],
  "shell": {
    "init_hook": [
      "echo 'Welcome to devbox!' > /dev/null"
    ],
    "scripts": {
      "test": [
        "echo \"Error: no test specified\" && exit 1"
      ]
    }
  }
}

Devbox version

0.13.4

Nix version

nix (Nix) 2.24.7

What system does this bug occur on?

Linux (x86-64)

Debug logs

No response

DerArkeN commented 1 month ago

have you tried putting the devbox eval to the very top of your first rc file?

rbhanot4739 commented 1 month ago

@DerArkeN what do you mean by first rc file ?Its already placed at the top in the minimal zshrc i shared above.

Lagoja commented 1 month ago

@rbhanot4739 Does this issue persist even after running refresh-global? Sometimes that error occurs if you've recently upgraded devbox

Lagoja commented 1 month ago

the BASH_FUNC() error that you are seeing is a Shellshock mitigation, because something in either your zshrc or system zshrc is trying to export a function, which is a security vulnerability. From the linked article:

Bash no longer generally interprets the x=() {...} environment variable as a function definition. Function definitions in environment variables are now required to be prefixed with BASHFUNC. Exporting functions with export -f x will now set a environment variable BASH_FUNC_x%%=() {...} instead of simply x=() {...}.

Can you check if there is a pathappend or pathprepend function exported in your shell rc?

rbhanot4739 commented 1 month ago

@Lagoja I am using zsh as my primary shell, the bashrc example was just for test i did in bash to check if it works in bash. No there is no pathappend or pathprepend in my .zshrc or .bashrc and both rc files were completely vanilla just containing devbox intitialization hook and couple of source commands. Also this is a fresh installation of devbox, so not sure why refresh-global warning is coming in first place.

I tried uninstalling devbox few times completely as per instructions in faqs and then installing it again but same issues pop up every time.

Lagoja commented 1 month ago

Which Linux Distro are you using? I can try to repro in a VM and see if it's a setting in the VM that we aren't handling

rbhanot4739 commented 1 month ago

I am using azure linux previously known as CBL Mariner

Lagoja commented 1 month ago

Ah yep, here it is:

https://github.com/microsoft/azurelinux/blob/3fc3abd10337c6a6db742f5ce79e1fcfb296dfd8/SPECS/zsh/zprofile.rhs#L10

It looks like Azure sets those functions in the zprofile, and Devbox trying to source and reexport them is what's causing the issue

EDIT: Doing some testing, this shouldn't be triggering the issue in ZSH, meaning either we are using Bash somewhere in the middle when sourcing the environment, or something on your system is prompting us to evaluate Bash as your default shell. Does your environment have the $SHELL variable set to bash by any chance?

rbhanot4739 commented 1 month ago

Yes, you are right, so the default shell for the user is being set by ldap profile. So yes initially the default login shell is bash but as a workaround, i do a exec zsh -l to in my bashrc to spawn zsh as my login shell. Wouldn't that fix this ? Also i am not loading devbox in bash profile.

But thank you so much for taking the time to troubleshoot this issue.

Lagoja commented 1 month ago

Can you try adding export SHELL=/bin/zsh to your zshrc, and see if that fixes the issue? I can check with the team as well to see if we should modify our detection logic to handle this case.

rbhanot4739 commented 1 month ago

@Lagoja I am already exporting SHELL=/bin/zsh as part of execing zsh from .bashrc but unfortunately it didn't work.

Here are the contents of it.

if [ -f "/etc/bash.bashrc" ]; then
  source /etc/bash.bashrc
fi
# End ~/.bashrc

if [[ $- == *i* ]]; then
        export SHELL=/bin/zsh
        exec -l /bin/zsh
else
    echo "not an interactive shell"
fi

And here is my .zshrc

eval "$(devbox global shellenv --init-hook)"
source <(fzf --zsh)
eval "$(zoxide init zsh)"
source ~/powerlevel10k/powerlevel10k.zsh-theme
[[ ! -f ~/.p10k.zsh ]] || source ~/.p10k.zsh
rbhanot4739 commented 1 month ago

@Lagoja Even exporting SHELL=/bin/zsh explicitly does not work.

$ export SHELL=/bin/zsh
$ zsh -l
❯ echo $SHELL
/bin/zsh
❯ eval "$(devbox global shellenv)"
export: not valid in this context: BASH_FUNC_pathappend%%

It looks shell initialization hook from .zshrc is not being picked up at all

$ cat .zshrc
eval "$(devbox global shellenv)"

$ exec -l zsh
(eval):export:1: not valid in this context: BASH_FUNC_pathappend%%
$ devbox global list
* ripgrep@latest - 14.1.1

Warning: devbox global is not activated.

Add the following line to your shell's rcfile (e.g., ~/.bashrc or ~/.zshrc)
and restart your shell to fix this:

        eval "$(devbox global shellenv)"

$ type refresh-global
refresh-global not found

Update:

Not sure why but the issue seemed to be the refresh-global not being available in zsh for me, so I replaced it with the actual command eval "$(devbox global shellenv --preserve-path-stack -r)" && hash -r and this seemed to did the trick for me. After I ran this command devbox was activated and the shell initialization hook seemed to load it.