Spawn a WSL subshell when the windows install is called from WSL - #33
Merged
Conversation
WSL users install keycmd on windows, so that keyring reaches the windows credential manager instead of a keyring daemon inside the distro. That leaves keycmd a windows process with a windows idea of a shell: it would hand the command to cmd, or open one for --shell, neither of which is what someone typing in a distro shell asked for. keycmd now works out whether it was called from a distro -- a wsl.exe or wslhost.exe ancestor decides it, a windows shell found first decides against it, and a working directory under \\wsl$ settles the rest -- and hands the command to wsl.exe when it was. KEYCMD_WSL overrides that decision in either direction, and --verbose reports which way it went. The credentials do not cross the boundary by themselves, since neither side inherits the other's environment, so get_env lists the variables it exposes in WSLENV, the only thing that does make the trip. Along the way, the COMSPEC fallback in get_shell now reports "cmd" rather than "cmd.exe", the way shellingham does, so that run_cmd recognizes it and passes /C instead of an option cmd does not know. Fixes #29
wsl.exe runs the default distribution unless it is told which one to run, which is the wrong one as soon as a machine has more than one installed. A working directory on a distribution's own file system reaches windows as a UNC path that names it, so pass it on as --distribution when it does.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #29.
The problem
With the WSL setup, keycmd is a windows process invoked from a shell inside a distribution. shellingham finds no shell in its windows ancestor chain, so
get_shellfalls back to%COMSPEC%: the command ran incmd, on the wrong side of the interop boundary, in a shell nobody asked for. The fallback also reported the shell ascmd.exe, whichrun_cmddid not match against its"cmd"check, so it builtcmd.exe -c "<command>"— an optioncmddoes not understand.The change
keycmd/wsl.py(new) decides whether keycmd was called from a distribution, and builds the command line for it:wsl.exe/wslhost.exe/wslservice.exeancestor decides for it; a windows shell found first decides against it (that is a windows shell run over interop, and its command belongs on windows); a working directory under\\wsl$\or\\wsl.localhost\settles the rest--distributionso a second distribution does not send the command to the default oneKEYCMD_WSL=0/1overrides the decision in either direction, and--verbosereports the process tree it walked and which way it wentkeycmd/shell.py:run_shellopens a shell in the distribution,run_cmdruns the command there (wsl.exe -- <cmd>, which hands it to the distribution's login shell, the counterpart of the-cused elsewhere). TheCOMSPECfallback now reportscmdrather thancmd.exe, the way shellingham does, which fixes the/Cpath for plain windows use too.keycmd/creds.py: credentials do not cross the boundary by themselves, since neither side inherits the other's environment. Only what is named inWSLENVmakes the trip, soget_envadds the keys and aliases it exposes to it, keeping whatever the user already shares, flags and all.Tests
tests/test_wsl_interop.pyfakes the windows process table and working directory, so detection, thewsl.execommand lines andWSLENVare covered on every platform. An autouseoutside_wslfixture keeps the rest of the suite off that code path, so a run on windows still looks like a run anywhere else.The opt-in end to end test in
tests/test_wsl.pynow runskeycmd --verbose printenv <VAR>from a WSL shell:printenvis a linux command, so reaching it at all means the command went back into the distribution, and it only sees the credential because ofWSLENV.ruff,tyand the suite pass locally (79 passed, 3 skipped — the skips are the opt-in end to end WSL tests).Worth a look before merging
The end to end tests are the only check on the real ancestor image names, and they need a windows machine with WSL:
If the process table turns out to say something else on your machine,
keycmd --verboseprints the chain it walked, and the working directory signal still covers the common WSL2 case of working on the distribution's own file system.Generated by Claude Code