Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/shells: Avoid overriding the environment for other child shells #44720

Closed
wants to merge 1 commit into from

Conversation

hedning
Copy link
Contributor

@hedning hedning commented Aug 8, 2018

Motivation for this change

fixes #33219

All new ZSH and Bash shells source system.build.setEnvironment if it's not already done by a parent shell of the same type.

For instance, if ZSH is the default shell, launching a Bash shell will reset any modifications to PATH.

One unfortunate effect of this behavior is nix run launching a bash shell with an incorrect PATH when run from ZSH in eg. the console or SSH (for some reason nix-shell isn't affected by this).

The broken nix run behavior is a blocker for #44497, as the environment is set up using a login shell of the users choice, ie. /etc/profile isn't sourced if using ZSH. In graphical sessions this was normally protected against by always sourcing /etc/profile

cc @oxij as you've written a large part of the shell environment setup

Things done

This adds a shared exported guard, __NIXOS_SET_ENVIRONMENT_DONE, that prevents
interactive non-login child shells of any type sourcing system.build.setEnvironment if
it's already done.

Login shells on the other will always reset the basic environment.

I tried using shopt -q login_shell to get the bash code to be more similar to ZSH, but that broke nixos.tests.login. Not that happy with the resulting flow of code in bash.nix, so if someone knows a more portable way to check for a login shell, that would be preferable I think.

I've done some basic testing using both ZSH and Bash as default shells in a VM. Also tested nixos.tests.login and nixos.tests.env.

I haven't looked Fish, but the guard should be set, so launching Bash from fish should work as expected.

  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nox --run "nox-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Fits CONTRIBUTING.md.

@oxij
Copy link
Member

oxij commented Aug 8, 2018 via email

@hedning hedning mentioned this pull request Aug 10, 2018
9 tasks
@oxij
Copy link
Member

oxij commented Aug 15, 2018 via email

@hedning
Copy link
Contributor Author

hedning commented Aug 15, 2018

I don't like how complicated this gets, especially in the bash case. AFAICS all the cited issues are about simple env reset. Why do you treat login shells differently then?

Yeah, the bash code gets pretty ugly. The reasoning came from @rycee's comment. When thinking it through I agree that preserving the semantics probably isn't worth the complications. And I'm not even sure if login shells clearing some of the environment is a common semantic?

If we're only sourcing the basic environment once then a common guard in setEnvironment should do the trick, which is far simpler :)

(Btw, I also think that this is a good time to rethink #30418. IMHO rc files that generates are pretty unreadable.)

Wrapping a huge block in if without indentation makes it nonviable at least.

@hedning hedning force-pushed the fix-shell-environment-clobber branch from ca95a95 to 7e28f87 Compare August 15, 2018 09:21
@hedning
Copy link
Contributor Author

hedning commented Aug 15, 2018

OK, pulled the whole guard into setEnvironment. To avoid the wrong indentation in the generated file I used return at the top to break out if already done. That also meant changing to . ${config.system.build.setEnvironment}.

This is a lot simpler, and should work correctly for fish shell too I believe.

@oxij
Copy link
Member

oxij commented Aug 15, 2018 via email

@hedning
Copy link
Contributor Author

hedning commented Aug 15, 2018

Agreed, it would be good to have grepability and easy access to source the common environment again.

/etc/environment is commonly used by systemd/pam and should be a simple list of VAR=VALUE without export or any expansion. So a more unique name, eg. /etc/common-environment, should be used. (Though moving to /etc/environment in the future is probably wanted).

@hedning
Copy link
Contributor Author

hedning commented Aug 17, 2018

Went with /etc/common-environment removing system.build.setEnvironment (didn't seem like much of a point eg. linking /etc/common-environment to system.build.setEnvironment).

@oxij
Copy link
Member

oxij commented Aug 18, 2018 via email

@hedning hedning force-pushed the fix-shell-environment-clobber branch from 2732736 to 0cbd181 Compare August 18, 2018 15:21
We move `system.build.setEnvironment` to `/etc/set-environment` making it
easy to grep for environment variables in `/etc` and resetting the common
environment if its wanted with `. /etc/set-environment`.

A shared exported guard, `__NIXOS_SET_ENVIRONMENT_DONE`, is introduced that can
be used to prevent child shells sourcing `/etc/set-environment` again if it's
already done.

This fixes eg. `nix run derivation` when run from eg. ZSH through the console or
ssh. Before this Bash would resource the common environment resetting `PATH`.
@hedning hedning force-pushed the fix-shell-environment-clobber branch from 0cbd181 to fecb9ab Compare August 18, 2018 15:21
@hedning
Copy link
Contributor Author

hedning commented Aug 18, 2018

I would call it /etc/set-environment, mainly for continuity with the old name, and since it's a script.

Good point.

Well, but having those files depend on each other and not on /etc has its merits.

Yeah, I'm fine with both. I guess referencing it from nix code means there's some checks at evaluation time at least.

@oxij
Copy link
Member

oxij commented Aug 30, 2018

I made an edited version of this with my comments applied in #45784.

Any comments?

Hint: if there're none then you can fetch from my repo and reset this branch to 8952375, push to github, and then merging either PR will close both.

@vcunat
Copy link
Member

vcunat commented Aug 30, 2018

I vaguely remember you commented on something similar.

I can't recall anything similar right now :-)

@hedning
Copy link
Contributor Author

hedning commented Sep 5, 2018

@oxij looks good 👍 , I'll just close this one.

@hedning hedning closed this Sep 5, 2018
@hedning hedning deleted the fix-shell-environment-clobber branch October 15, 2019 11:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

XDG_DATA_DIRS reinitalized to an incomplete value by zshenv
4 participants