1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2026-02-04 07:51:50 +00:00

Add option for wsl_shell_type, protect wsl.exe arguments if SSH shell is Powershell (#11308)

* feat(wsl): add option for wsl_shell_type, protect wsl arguments if SSH shell is Powershell

* docs(wsl): add changelog fragment

* docs(wsl): fix changelog fragment syntax, add issue link

Co-authored-by: Felix Fontein <felix@fontein.de>

* feat(wsl): improve new option documentation

Co-authored-by: Felix Fontein <felix@fontein.de>

* refactor(wsl): put integrasion test flag into a variable for convenience

* feat(wsl): rename option to wsl_remote_ssh_shell_type

* feat(wsl): escape "%" if shell is cmd, raise AnsibleError if powershell

* test(wsl): fix unit tests for wsl

- remove redundant check - moved to a separate function
- fix check for cmd escaping of "%"
- fix formatting / whitespace

* test(wsl): fix expected error message

* test(wsl): fix test - position of stop-parsing token changed

Co-authored-by: Felix Fontein <felix@fontein.de>

---------

Co-authored-by: Felix Fontein <felix@fontein.de>
This commit is contained in:
fizmat 2026-01-17 00:07:11 +04:00 committed by GitHub
parent 4b0aeede69
commit 4b67afc2b0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 45 additions and 3 deletions

View file

@ -0,0 +1,3 @@
minor_changes:
- wsl connection plugin - add option ``wsl_remote_ssh_shell_type``. Support PowerShell in addition to cmd as the Windows
shell (https://github.com/ansible-collections/community.general/issues/11307, https://github.com/ansible-collections/community.general/pull/11308).

View file

@ -231,6 +231,18 @@ options:
required: true
vars:
- name: wsl_distribution
wsl_remote_ssh_shell_type:
description:
- The shell type expected in the SSH session (not inside the WSL session).
- See also C(ansible_shell_type).
type: string
choices:
- cmd
- powershell
default: cmd
vars:
- name: wsl_remote_ssh_shell_type
version_added: 12.2.0
wsl_user:
description:
- WSL distribution user.
@ -578,17 +590,31 @@ class Connection(ConnectionBase):
wsl_distribution = self.get_option("wsl_distribution")
become = self.get_option("become")
become_user = self.get_option("become_user")
wsl_remote_ssh_shell_type = self.get_option("wsl_remote_ssh_shell_type")
is_integration_test = os.getenv("_ANSIBLE_TEST_WSL_CONNECTION_PLUGIN_WAERI5TEPHEESHA2FAE8")
if "%" in cmd:
if wsl_remote_ssh_shell_type == "powershell":
# there is no universal way to escape '%' here
# if this is raised, add a workaround to allow the specific situation (if possible)
raise AnsibleError("The command contains '%', cannot safely escape it for Powershell")
else:
cmd = cmd.replace("%", "^%")
if become and become_user:
wsl_user = become_user
else:
wsl_user = self.get_option("wsl_user")
args = ["wsl.exe", "--distribution", wsl_distribution]
args = ["wsl.exe"]
if wsl_remote_ssh_shell_type == "powershell" and not is_integration_test:
# Powershell stop-parsing token, treat the rest as arguments to the native command wsl.exe
args.append("--%")
args.extend(["--distribution", wsl_distribution])
if wsl_user:
args.extend(["--user", wsl_user])
args.extend(["--"])
args.extend(shlex.split(cmd))
if os.getenv("_ANSIBLE_TEST_WSL_CONNECTION_PLUGIN_WAERI5TEPHEESHA2FAE8"):
if is_integration_test:
return shlex.join(args)
else:
return list2cmdline(args) # see https://github.com/python/cpython/blob/3.11/Lib/subprocess.py#L576
def exec_command(self, cmd: str, in_data: bytes | None = None, sudoable: bool = True) -> tuple[int, bytes, bytes]:

View file

@ -210,6 +210,19 @@ def test_build_wsl_command(connection):
assert cmd == 'wsl.exe --distribution test --user test-become-user -- /bin/sh -c "ls -la"'
def test_build_wsl_command_powershell(connection):
"""Test wsl command building for powershell and cmd remote ssh shell"""
cmd = connection._build_wsl_command('/bin/sh -c "ls -la %PATH%"')
assert cmd == 'wsl.exe --distribution test -- /bin/sh -c "ls -la ^%PATH^%"'
connection.set_option("wsl_remote_ssh_shell_type", "powershell")
cmd = connection._build_wsl_command('/bin/sh -c "ls -la"')
assert cmd == 'wsl.exe --% --distribution test -- /bin/sh -c "ls -la"'
with pytest.raises(AnsibleError, match="The command contains '%', cannot safely escape it for Powershell"):
connection._build_wsl_command('/bin/sh -c "ls -la %PATH%"')
@patch("paramiko.SSHClient")
def test_exec_command_success(mock_ssh, connection):
"""Test successful command execution"""