stelios
stelios

Reputation: 91

Source bashrc in WSL in a non-interactive, non-login shell

I am working on a project, and I have a problem with WSL and bashrc. To elaborate a little bit, I have keychain and I want to run a keychain command every time I use a WSL command.

So I added that command in my ~./bashrc.

If from my Windows Terminal I use wsl bash -ic "command", my command inside ~/.bashrc runs.

My problem now is that I have another program that runs WSL without the bash -ic params, and I can't change that.

Do you know how I can address this problem or find a workaround?

Basically, I want it so that every time I use WSL from my Windows Terminal, it runs the keychain command first.

For example, let's say that I want to run wsl git push. I want my keychain command to execute before the git push runs.

Upvotes: 4

Views: 2227

Answers (3)

gerardnico
gerardnico

Reputation: 1073

It will work natively with some configuration.

The problem is that git is run with the wsl command line in non-interactive, non-login shell such as

wsl git ...

Therefore it does not get the SSH_AGENT_SOCK. You can see it by running from windows

wsl env

To pass it on, you can use the WSLENV feature

I describe below the steps that I follow

In your WSL .bashrc, start the agent by providing the location of the socket. To start it only once, adapt this code

export SSH_AGENT_SOCK=~/.ssh/agent.sock
ssh-agent -a $SSH_AGENT_SOCK

Then in Windows, add the following variables:

  • SSH_AGENT_SOCK with the same value as in WSL
set SSH_AGENT_SOCK=/home/username/.ssh/agent.sock
  • allow SSH_AGENT_SOCK to be passed as env in the wsl command
set WSLENV=SSH_AGENT_SOCK

Restart your terminal and check that you get the SSH_AGENT_SOCK in WSL

wsl env

Then restart IDEA and it should work if you have open at least once, a terminal to start the ssh-agent

All the best

Upvotes: 0

NotTheDr01ds
NotTheDr01ds

Reputation: 20821

Well, I've noodled on this on-and-off for several days to see if I could come up with a better solution. Nothing I can think of is optimal, but I think I ended up pretty close.

To restate/frame the problem:

  • You need a WSL distribution to run a certain interactive command (keychain) that loads its environment variables into the user's WSL/Bash session. This needs to happen to load the key into ssh-agent so that wsl git commands in IntelliJ will work with your plugin.

  • keychain will ask for a password for the key to be loaded if one is required.

  • keychain will output the environment variables needed for ssh-agent in a format that can be evaluated/sourced back into the Bash session.

    (Side-note: It's really lucky that I've been using keychain for a couple of decades now, so I know its process flow fairly well).

  • When run with wsl git ..., WSL launches the shell (Bash) as a non-interactive, non-login shell, so ~/.bashrc is not processed. Because of this, even if the key had been previously loaded into ssh-agent (by keychain), the Bash session does not have the proper SSH_AUTH_SOCK and SSH_AGENT_PID.

As a result of this, the git commands in your plugin are likely to fail for the user, since they require key-based authentication.

I think the above at least captures the spirit of the problem you are trying to solve.

Unfortunately, there's just no method that I'm aware of to force Bash to load its startup files when it is a non-interactive, non-login shell other than things that would modify the WSL command-line.

Proposed workaround - $WSLENV chain-loading IntelliJ

This is "pretty close" to optimal, I believe. Your users would need to launch IntelliJ through WSL and use the $WSLENV feature to pass through the correct environment variables. This could be done interactively or through ~/.bashrc.

Add the following to ~/.bashrc:

eval $(keychain --eval ~/.ssh/<keyfile>)
export WSLENV=$WSLENV:SSH_AGENT_PID:SSH_AUTH_SOCK

With this in place, you should be able to run:

wsl -e bash -lic /path/to/intellij.exe

It will ask for the key password and (as normal) add the SSH_AGENT_PID/SSH_AUTH_SOCK environment variables to the shell session. It will also add those variable names to $WSLENV, so that they are passed to any Windows process launched from inside WSL.

When the IntelliJ Windows executable is launched this way, the three variables will also be available in its environment:

  • WSLENV
  • SSH_AGENT_PID
  • SSH_AUTH_SOCK

And when IntelliJ then runs wsl git ..., those three variables will also be passed back into WSL, so that git will be able to access the key from ssh-agent.

While I don't have IntelliJ, I've tested this successfully using:

wsl -e bash -lic pwsh.exe # or powershell.exe

Then, from PowerShell:

> $env:WSLENV
WT_SESSION::WT_PROFILE_ID:SSH_AGENT_PID:SSH_AUTH_SOCK

> $env:SSH_AGENT_PID
45

> $env:SSH_AUTH_SOCK
/tmp/ssh-XXXXXXTWbsTa/agent.44

> cd some-dir
> wsl git clone "[email protected]:NotTheDr01ds/<private_repo>"

It worked as expected.

Other options

This is actually a bit easier if your users are using (or open to using) some shells other than Bash:

  • The Fish shell startup files that are sourced even for non-login, non-interactive shells plus it supports "universal variables" that allow the SSH_A* variables to automagically be made available to all running (and future) Fish instances.

  • Zsh has a startup file (~/.zshenv) that is sourced for non-login, non-interactive shells. It's a little more complicated than Fish, but it's workable.

I actually started with these as proposed solutions before I found that $WSLENV was a workable solution (that didn't require a shell change). However, if you want to see my write-up on how to do this in Zsh or Fish, just look at the edit history for this answer.

Upvotes: 3

zvi
zvi

Reputation: 4756

On Windows 11 you can run script when wsl is starting, create or edit (as sudo) /etc/wsl.conf with the following contents:

[boot]
command="command to run"

Add there the commands you want.

Upvotes: 0

Related Questions