Skip to content

fix(install): tell WSL 1 from WSL 2 by the kernel release, not by wsl.exe's wording - #7677

Open
paulovillani wants to merge 1 commit into
shellhub-io:masterfrom
paulovillani:fix/install-wsl-version-detection
Open

paulovillani wants to merge 1 commit into
shellhub-io:masterfrom
paulovillani:fix/install-wsl-version-detection

Conversation

@paulovillani

Copy link
Copy Markdown

Summary

The installer refuses WSL 2 distros on a Windows whose display language is not English. It runs wsl.exe --version and greps the English label WSL version; a Windows in Portuguese prints Versão do WSL: 3.0.3.0, so the version comes out empty and the install stops with "WSL version 2 is required". The inbox wsl.exe, which has no --version, and a C: drive not mounted under /mnt end the same way. What that command prints is also the version of the WSL package, not the version the distro runs under (wslinfo --wsl-version prints the same WSL_PACKAGE_VERSION): the 1.x Store packages of 2023 ran WSL 2 distros and were refused, which is what the old test fed it as "too old" (1.2.5.0), while a WSL 1 distro under a 2.x or 3.x package passed and only failed later at systemctl or wslinfo.

 detect_install_method
   /proc/version mentions Microsoft
-    wsl.exe --version | grep "WSL version"          -> the package version, English only
-      empty or below 2                               -> exit 1
+    third word of /proc/version (the kernel release)
+      4.4.0-<build>-Microsoft or 3.4.0-Microsoft     -> WSL 1, exit 1
+      anything else                                  -> WSL 2, go on
     /etc/os-release is not Ubuntu                   -> exit 1

WSL 1 has no kernel of its own and reports a fixed compatibility release, 4.4.0-<build>-Microsoft (3.4.0-Microsoft on the 2016 builds). WSL 2 runs a real kernel; Microsoft's is built with CONFIG_LOCALVERSION="-microsoft-standard-WSL2" (5.15.y, 6.6.y). Refusing only the WSL 1 releases and taking anything else under WSL as WSL 2, custom kernels included, is the rule Microsoft's own .NET Aspire CLI applies in WslEnvironmentCheck.cs: WSL 1 is ^(?:4\.4\.0-\d+-Microsoft|3\.4\.0-Microsoft)$, Microsoft's WSL 2 kernels are ^\d+(?:\.\d+)+-(?:microsoft-standard(?:-WSL2)?|microsoft-WSL2-standard)$ (lines 243 to 255), and any other release is WSL 2 once the environment has said it is WSL at all, which /proc/version has by the time this case runs. The comments there also say why the 4.4.0 must not be compared as a version number. And /proc/version and osrelease are where the WSL team pointed detection at from the start. The installer already reads /proc/version to know it is on WSL, so the release costs it nothing new.

#4364 read the distro's line of wsl.exe -l -v through grep $WSL_DISTRO_NAME; #5230 moved to --version, presumably to drop the environment variable and the substring match. This check uses no wsl.exe, no mount, no environment variable and no language, so it keeps what #5230 gained and removes what it lost.

Evidence

  • Before: on a WSL 2 Ubuntu under a Windows in Portuguese (Windows 11 24H2, WSL package 3.0.3.0, kernel 6.18.54.1), curl -sSf .../install.sh | sh prints 🔍 Detected WSL environment... then ❌ ERROR: WSL version 2 is required to run ShellHub. There, wsl.exe --version | tr -d '\0' begins with Versão do WSL: 3.0.3.0, and wsl.exe -l -v lists Ubuntu Running 2. The command was run with INSTALL_METHOD=standalone, which the check does not honour either.
  • After: on the same machine the third word of /proc/version is 6.18.54.1-microsoft-standard-WSL2, which the new case lets through.
  • install.bats: "detection aborts when WSL is older than version 2" fed the package version 1.2.5.0, which ran WSL 2 distros; it is replaced by "detection aborts on WSL 1" (4.4.0-19041-Microsoft) and "detection treats a WSL 2 custom kernel as WSL 2" (6.1.0-custom-WSL2). enter_wsl now writes a realistic /proc/version banner and no longer stubs find and wsl.exe. bats install.bats shellhub-agent-wrapper.bats: 167 of 168 pass on this branch. The one failure, standalone_uninstall looks in the default install dir when the environment names none, fails the same way on master on the machine that ran it, because it has a real /usr/local/bin/shellhub-agent; it does not touch the changed code.
  • shellcheck -s sh -S warning install.sh is clean; devscripts/comment-scan reports nothing on both files.

Merge Danger

Door: two-way

Reverting the commit restores the old check. Nothing is stored or migrated.

Blast Radius: WSL installs

A WSL 1 distro keeps getting the "WSL version 2 is required" message, whichever WSL package is installed. A WSL 2 distro on a custom kernel, which the old check judged by the package version, now goes on to the WSL method, where systemctl and wslinfo still gate it. A non-English Windows installs.

Closes #7676

….exe's wording

The installer refused WSL 2 distros on any Windows whose display language
is not English. It ran "wsl.exe --version" and grepped the English label
"WSL version"; a Windows in Portuguese prints "Versão do WSL: 3.0.3.0"
instead, so the version came out empty and the installer stopped with
"WSL version 2 is required". The inbox wsl.exe, which has no --version,
and a C: drive not mounted under /mnt ended the same way. What that command
prints is also the version of the WSL package, not the version the distro
runs under (wslinfo --wsl-version prints the same WSL_PACKAGE_VERSION): the
1.x Store packages of 2023 ran WSL 2 distros and were refused, which is what
the old test fed it as "too old", and a WSL 1 distro under a 2.x or 3.x
package passed and failed later on systemd or wslinfo.

WSL 1 has no kernel of its own and reports the fixed compatibility release
"4.4.0-<build>-Microsoft" ("3.4.0-Microsoft" on the 2016 builds). WSL 2 runs
a real kernel; Microsoft's reads "-microsoft-standard-WSL2", from
CONFIG_LOCALVERSION in microsoft/WSL2-Linux-Kernel. So the installer now
reads the release from /proc/version, which it already consults to tell it
is on WSL, and refuses only the WSL 1 releases. Anything else under WSL is
WSL 2, custom kernels included, which is the rule Microsoft's own .NET Aspire
CLI applies in WslEnvironmentCheck.cs (microsoft/aspire@c94dbb82, lines 142
to 192 and 243 to 255). No wsl.exe, no mount, no environment variable and no
language take part, so the check also keeps what shellhub-io#5230 set out to gain over
the earlier "wsl.exe -l -v | grep $WSL_DISTRO_NAME".

Fixes: shellhub-io#7676
@paulovillani
paulovillani requested a review from a team as a code owner October 23, 2026 21:49
@otavio

otavio commented Oct 25, 2026

Copy link
Copy Markdown
Member

/review

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

Claude finished @otavio's task in 2m 52s —— View job


Code Review Complete

Reviewed 2 files. 1 inline issue posted. Standards: 0 violations, 1 judgement call. Spec: 0. Correctness: 0.

Standards

The only finding is a judgement call on install.bats:1493. The "WSL 2 custom kernel" test passes the WSL gate only because enter_wsl always writes (Microsoft@Microsoft.com) into the fake /proc/version. A real self-built kernel has no "microsoft" there, so the installer would never detect WSL. The test name claims more than the code does.

Spec

Issue #7676 is fully met. The check no longer depends on the language of Windows, on where wsl.exe lives, or on C: being mounted, because it now reads the kernel release from /proc/version. A WSL 1 release (4.4.0-<build>-Microsoft, and 3.4.0-Microsoft on the 2016 builds) gets "WSL version 2 is required". Any other release goes on to the WSL install method.


If you've addressed the feedback and want a new review, tag
@shellhub-io/core and a team member can trigger it.

Comment thread install.bats
Comment on lines +1493 to +1494
@test "detection treats a WSL 2 custom kernel as WSL 2" {
enter_wsl 6.1.0-custom-WSL2

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Standards (judgement call): this test promises more than the installer does. 6.1.0-custom-WSL2 has no "microsoft" in it, so the test gets past the WSL gate (grep -qi Microsoft at install.sh:812) only because enter_wsl (line 80) always writes (Microsoft@Microsoft.com) as the build host. That host string comes from WSL 1's banner. A kernel someone builds themselves reports their own user@host there, so its /proc/version has no "microsoft" anywhere. The installer would not see WSL at all and would never reach the new case. This is the same as before the PR, so it is not a regression. But the test name, and the Blast Radius line ("A WSL 2 distro on a custom kernel ... now goes on to the WSL method"), claim behaviour that real custom kernels don't get. The tdd skill: "A good test reads like a specification".

What the test actually pins is that a kernel release outside Microsoft's naming, once the WSL gate has passed, is not refused as WSL 1. Either rename it to say that, or make the build host a second enter_wsl argument so the fixture states where the "Microsoft" match comes from. For example:

Suggested change
@test "detection treats a WSL 2 custom kernel as WSL 2" {
enter_wsl 6.1.0-custom-WSL2
@test "detection lets a non-WSL-1 kernel release through once /proc/version names Microsoft" {
enter_wsl 6.1.0-custom-WSL2

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

install.sh refuses WSL 2 on a Windows whose display language is not English

2 participants