Skip to content

feat: Add versioned distributions, replace non-versioned Alpine and Debian with wsl --import#85

Merged
Vampire merged 8 commits intoVampire:masterfrom
exoego:wsl-import
Apr 10, 2026
Merged

feat: Add versioned distributions, replace non-versioned Alpine and Debian with wsl --import#85
Vampire merged 8 commits intoVampire:masterfrom
exoego:wsl-import

Conversation

@exoego
Copy link
Copy Markdown
Contributor

@exoego exoego commented Apr 4, 2026

Changes

  • Debian
    • Add "Debian-11" (bullseye). "Debian-12" (bookworm) and "Debian-13" (trixie) using .wsl files from Salsa.
    • Deprecate "Debian" (bullseye, stale aka.ms shortlink with broken backports).
    • Default distribution changed to "Debian-11" for backward compatibility.
  • Alpine
    • Add "Alpine-3.17" ... "Alpine-3.23" using official minirootfs tarballs.
    • Deprecate the broken "Alpine" (third-party MS Store API permanently blocked) which now points to the last-working Alpine-3.17
  • Both new distribution types are installed via wsl --from-file --no-launch with fallback to wsl --import, instead of the AppxBundle installer.
  • Remove dead productId / rg-adguard API code, Ktor
  • Make installation method, user creation, and cache filename handling distribution-aware.

This is a breaking change as distributions get major version bumps.
I think it is a good timing to bundle with #84 (Node.js major version bump).

@Vampire
Copy link
Copy Markdown
Owner

Vampire commented Apr 4, 2026

Thanks for your effort, really appreciate it.
From a cursory look it is roughly what I had in mind too.
Did not yet review in detail.
But some points so far:

  • Shouldn't .wsl be installed using wsl --install --from-file ... (https://learn.microsoft.com/en-us/windows/wsl/build-custom-distro) and only arbitrary Linux distros with wsl --import ... (https://learn.microsoft.com/en-us/windows/wsl/use-custom-distro)?
  • I don't think we should make a breaking change for Debian. As long as it is not tried to be updated or if the URL is fixed by a user script first it can still work just fine, so I don't see why we should break it. I think instead we should deprecate "Debian" (thought version might change over time) and instead have that as "Debian-11" with writing a GHA warning about the deprecation. And then we can additionally have "Debian-12" and "Debian-13" with the new tactic.
  • For Alpine it is slightly different, as there the version was indeed potentially changing by requesting the current download link from the Microsoft Store. Now with fixed links I think we can also have concrete ones like "Alpine-3.20", "Alpine-3.21", "Alpine-3.22", "Alpine-3.23". There we might just remove the "Alpine" one with the major version bump as it is broken right now anyway. Or maybe still have "Alpine" but deprecated like with debian, using the version with which it last worked if it can be found out. That way if an action was not run for long time and now is tried to run it will continue to work without break.
  • Does the wsl.conf on debian have content? If so, is it right to just overwrite it? If so, this should be documented (Debian-independent in the docs), and maybe the old contents logged if action debugging is enabled. If it just is present as an empty file, the check should not be suppressed for Debian but changed so that empty file is also fine, but we still recognize if it changes in the future.
  • If we do need to have a dependency on multiple distributions in the tests, maybe better make getSuccess{Not,}OnDistributionCondition functions able to work with multiple distributions? But as written above, maybe that should not be necessary.
  • Shouldn't the useWslImport be a constructor argument like the others? Besides that it probably needs to be an enum if there are three ways to install. Or maybe we can just check the extension of the installer file? If it is .tar.gz or .tgz then import, if it is .wsl then install from file, if it is exe then appx-based, otherwise error or something like that.
  • The whole productId / _downloadUrl stuff and so on can be deleted, it was only for usage with that tool that stopped working with bots, so the code is effectively dead
  • Also the installerFile stuff is probably not necessary for the new ways? Iirc it was because I extract that from the downloaded appx and cache that separately, but if that file is directly downloaded, ...
  • Better make it configurable in the distribution how to add a user instead of trying one way and if it fails then another. Otherwise it maybe fails due to some other reason and it also has the second way and uses it successfully for some reason, and it also makes each run slower by first using the wrong way when it could right away know the correct command to issue.

@exoego
Copy link
Copy Markdown
Contributor Author

exoego commented Apr 5, 2026

@Vampire Thanks for the review.
I think I have addressed all points.
And all checks passed ✅ in my fork repo: exoego#1

Shouldn't .wsl be installed using wsl --install --from-file ... and only arbitrary Linux distros with wsl --import ...?

Tried implementing wsl --install --from-file, but it prompts for interactive UNIX user creation and hangs in CI environments.
Many WSL users demands but there is no flag to skip this 🤷‍♂️ :

Running the OOBE is the intended behavior.
So Both .wsl and .tar.gz now use wsl --import.
The InstallMethod enum retains WSL_FILE and TARBALL as distinct values so we can split the code paths if --from-file gains a non-interactive mode in the future.

I don't think we should make a breaking change for Debian. As long as it is not tried to be updated or if the URL is fixed by a user script first it can still work just fine [...] deprecate "Debian" [...] and instead have that as "Debian-11" [...] And then we can additionally have "Debian-12" and "Debian-13" with the new tactic.

Done. "Debian" still points to the old bullseye AppxBundle URL and emits a deprecation warning in refresh().
"Debian-11" is registered as an alias.
"Debian-12" (bookworm, Salsa v1.20.0) and "Debian-13" (trixie, Salsa v1.24.0) are added.
The default distribution is changed to "Debian-13".

For Alpine [...] we can also have concrete ones like "Alpine-3.20", "Alpine-3.21", "Alpine-3.22", "Alpine-3.23". There we might ust remove the "Alpine" one with the major version bump as it is broken right now anyway.

Done. "Alpine" is removed since the MS Store API is permanently broken and the last working version cannot be determined.
Alpine-3.20 (3.20.9), Alpine-3.21 (3.21.6), Alpine-3.22 (3.22.3), and Alpine-3.23 (3.23.3) are added using official minirootfs tarballs.

Does the wsl.conf on debian have content? If so, is it right to just overwrite it? If so, this should be documented [...] and maybe the old contents logged if action debugging is enabled.

Debian-13 ships with [boot]\nsystemd=true in /etc/wsl.conf.
Existing contents are now logged in debug mode before overwriting.
The overwrite behavior is documented in the wsl-conf input description in action.yml.
The test now accepts either a missing file or known default content via diff, rather than suppressing per-distribution.

If we do need to have a dependency on multiple distributions in the tests, maybe better make getSuccess{Not,}OnDistributionCondition functions able to work with multiple distributions?

The wsl.conf test was rewritten to use printf ... | diff to validate content, so per-distribution exclusions are no longer needed and the vararg enhancement was not necessary.

Shouldn't the useWslImport be a constructor argument like the others? Besides that it probably needs to be an enum if there are three ways to install. Or maybe we can just check the extension of the installer file?

Done. Replaced useWslImport boolean with an InstallMethod enum (APP_BUNDLE, WSL_FILE, TARBALL) derived from the file extension of the download URL or installerFile.

The whole productId / _downloadUrl stuff and so on can be deleted, it was only for usage with that tool that stopped working with bots, so the code is effectively dead

Done. Removed productId constructors, _downloadUrl nullable pattern, rg-adguard API calls, Ktor HTTP client, and echo debug endpoint.
All distributions now have a direct downloadUrl: URL.

Also the installerFile stuff is probably not necessary for the new ways? Iirc it was because I extract that from the downloaded appx and cache that separately, but if that file is directly downloaded, ...

Done. installerFile is now String? (default null), only set for AppxBundle distributions (.exe).
For .wsl and .tar.gz, the cache filename is derived from the download URL via downloadFileName.

Better make it configurable in the distribution how to add a user instead of trying one way and if it fails then another.

Done. Added open suspend fun createUser(username: String) to Distribution (default: useradd), overridden in ApkBasedDistribution to use adduser -D. writeWslShellWrapper() calls distribution.createUser() directly.

@exoego exoego changed the title feat: Switch Debian and Alpine to wsl --import based installation feat: Add versioned Debian distributions, replace Alpine and deprecate Debian with wsl --import Apr 5, 2026
@exoego exoego changed the title feat: Add versioned Debian distributions, replace Alpine and deprecate Debian with wsl --import feat: Add versioned distributions, replace Alpine and deprecate Debian with wsl --import Apr 5, 2026
@exoego exoego changed the title feat: Add versioned distributions, replace Alpine and deprecate Debian with wsl --import feat: Add versioned distributions, replace non-versioned Alpine and Debian with wsl --import Apr 5, 2026
@Vampire
Copy link
Copy Markdown
Owner

Vampire commented Apr 5, 2026

Wow, nice, thanks.
Will hopefully find time for an in-depth review in the next days and either send some more comments or do some polishing myself if you don't mind. :-)

Tried implementing wsl --install --from-file, but it prompts for interactive UNIX user creation and hangs in CI environments.
Many WSL users demands but there is no flag to skip this 🤷‍♂️ :

Don't you send me my own discussion? :-D
Especially one that contains how to work-around it. :-D

Anyway, how about using --no-launch?
Iirc that should skip the first launch on install and thus also effectively skip the oobe Skript that tries to create the user interactively.
Then it also matches better the current docs that the user usually is root. :-D

Done. "Debian" still points to the old bullseye AppxBundle URL and emits a deprecation warning in refresh().
"Debian-11" is registered as an alias.

You also deprecated Debian-11, why?
In case I was unclear, I just intended "Debian" to be deprecated, but "Debian-11" is usable perfectly fine, so I don't see a reason to deprecate it right now.
Just wanted it as rename to make it clear which version it installs.

Debian-11 should then of course also be added to the tests.
Debian can be left out as long as it is just a deprecated alias.
Change of the default to Debian-13 would have been fine for me if we would do a major bump due to "Alpine" removal and Node.js bump. But I think we can restore "Alpine" back to working so I'd like to get these changes into a non-breaking release and then do the Node.js bump as a separate breaking release, so "Debian-11" should stay (become) the default for this PR.


Btw. about the createUser thing, is that something that changed in Alpine?
It used to work with useradd when Alpine last worked.

Had a few minutes and checked myself.
The Microsoft Store Alpine WSL distribution has the shadow package installed, which replaces the BusyBox login stack by the PAM login stack and brings the useradd along.

But I agree that it is better to not do that for the new way but use adduser instead.
But please only for the concrete distributions where it is known to be necessary, so for the alpine distributions.
Maybe configured in an AlpineDistribution subclass of ApkBasedDistribution as long as it is the same for all Alpine dists?

Other apk based dists in the future could support useradd like Alpine used to and if it is available, it is preferable for this use-case.

Done. "Alpine" is removed since the MS Store API is permanently broken and the last working version cannot be determined.

Why not?
There are several options.
You can just manually use the tool the action called and look what URL it generated.
Also I run daily integ tests to see when something breaks.
First failing run was https://github.com/Vampire/setup-wsl/actions/runs/21810427046/job/62921411980,
last working run was https://github.com/Vampire/setup-wsl/actions/runs/21791115789/job/62870586981.

The "Alpine" version is "3.17" for which also a minirootfs tarball exists.
So I'd prefer to do it the same as with Debian, making "Alpine" a deprecated alias for "Alpine-3.17" and consequently then also have 3.18 and 3.19 as options.

The wsl.conf test was rewritten to use

That was actually just the precondition to ensure what the action should do is not there yet.
The actual test only checks that the file exists and the effect.
Maybe it would make sense to also check the content for the expected one instead of just file existence now?

Removed [...] Ktor HTTP client

Is ktor still used somewhere?
Afair it was only used there and I had to add some nasty search-and-replace bugfixes in the build script for it.
If ktor is not used anymore, the dependency and the work-arounds should also be removed.

If I start to annoy you, just tell me, then I also can do the polishings probably, after you did really great work so far, thanks again. :-)

@Vampire
Copy link
Copy Markdown
Owner

Vampire commented Apr 5, 2026

If the proper --from-file does work, I think we should also use the .wsl files for the existing options where available, like for Ubuntu 20.04+ as it saves from downloading more than necessary and then multi-extracting nested archives before being able to install, so this should speed up things.

We can also support additional distributions as for example listed on https://github.com/microsoft/WSL/blob/master/distributions/DistributionInfo.json, but that should probably be done separately later.

@Vampire
Copy link
Copy Markdown
Owner

Vampire commented Apr 5, 2026

Oh, and the new dists are missing in the action-types.yml. (There also deprecated ones need to stay)

@Vampire
Copy link
Copy Markdown
Owner

Vampire commented Apr 5, 2026

And the dists and doc update in the readme template

@exoego exoego marked this pull request as draft April 6, 2026 11:36
@exoego
Copy link
Copy Markdown
Contributor Author

exoego commented Apr 6, 2026

@Vampire I think the 2nd review batch were all addressed now.
730 (!!) check passed in exoego#1
The tests are a bit flaky seemingly, retry might be needed.

how about using --no-launch?

Oh, I overlooked it.
Done. .wsl files now use wsl --install --from-file --no-launch --name <wslId>, with a fallback to wsl --import on older WSL versions (e.g. windows-2022) where --from-file is not available.

You also deprecated Debian-11, why? [...] "Debian-11" is usable perfectly fine [...] "Debian-11" should stay (become) the default for this PR.

Fixed. "Debian-11" is now an independent, non-deprecated distribution (not an alias for "Debian").
Default distribution is changed to "Debian-11" for backward compatibility.

The Microsoft Store Alpine WSL distribution has the shadow package installed [...] But please only for the concrete
distributions where it is known to be necessary [...] Maybe configured in an AlpineDistribution subclass of ApkBasedDistribution?

Done. Introduced AlpineDistribution as an intermediate subclass between ApkBasedDistribution and the concrete Alpine objects.
Only AlpineDistribution overrides createUser() to use adduser -D.
ApkBasedDistribution retains the default useradd.

So I'd prefer to do it the same as with Debian, making "Alpine" a deprecated alias for "Alpine-3.17" and consequently then also have 3.18 and 3.19 as options.

Done. "Alpine" is restored as a deprecated distribution pointing to Alpine 3.17 (the last working MS Store version). Alpine-3.17, 3.18, and 3.19 are added alongside the existing 3.20–3.23.

Maybe it would make sense to also check the content for the expected one instead of just file existence now?

Done. The wsl.conf tests now verify content via printf ... | diff after writing, instead of only checking file existence.

Is ktor still used somewhere? [...] If ktor is not used anymore, the dependency and the work-arounds should also be removed.

Done. Removed Ktor dependencies and the KTOR-6158 workaround.

If the proper --from-file does work, I think we should also use the .wsl files for the existing options where available, like for Ubuntu 20.04+

Good idea. --from-file --no-launch is now confirmed working in CI with Debian-12/13 (with --import fallback on windows-2022 where --from-file is not available).
I'd prefer to tackle Ubuntu .wsl migration in a follow-up PR to keep this one focused on the Debian/Alpine fixes.

Oh, and the new dists are missing in the action-types.yml. [...] And the dists and doc update in the readme template

Done. All distributions (including deprecated ones) added to action-types.yml and readme/README_template.md. The wsl.conf documentation now mentions Debian-13 alongside Ubuntu-24.04 as distributions that ship with a default wsl.conf.

@exoego exoego marked this pull request as ready for review April 6, 2026 13:19
@Vampire
Copy link
Copy Markdown
Owner

Vampire commented Apr 9, 2026

730 (!!) check passed in exoego#1

Actually 365, they were run twice due to the push and pull_request trigger. :-)
But the number will indeed raise a bit as you forgot to add Debian 11 and Alpine 17-19 to the tests, as well as the deprecated ones, as long as they are there they should be tested as working. :-)
So 509 it is now.

The tests are a bit flaky seemingly, retry might be needed.

Yeah, unfortunately.
That usually is because sometimes on wsl --update Microsoft servers answer with 403 and once they do, no direct retry fixes it.
I have a retry of 10 currently for that call, but once it fails it stays stubborn and only a manual retry helps.
Maybe because the next run is from a different agent with a different IP and it works or something like that.
If you have any idea for that one or a solution, I'd happily listen. :-)

Anyway, I took this also as an opportunity and did some maintenance.
I did on master

  • apply the work-around for Debian as it will stay and not be updated via link updating as I originally thought
  • updated various build logic and dependencies to latest versions
  • removed the KTOR work-around, it was already obsolete since update to 3.1.2

Actually the Kotlin update was the main reason, because I wanted to have guarded when-clauses available to simplify the installer code. :-)

I merged my changes on master into your PR branch.
And after a detail review I decided to make one additional commit on your PR branch,
that does some polishing and fixes some bugs and shortcomings I still found.

Maybe you want in turn now review my change? :-)
The main things I changed were:

  • added debian, debian-11, alpine, and alpine 17-19 to the tests
  • changed the wsl.conf pretest conditions, the only relevant point is, that it is not what we want to change it to before, but after
  • fixed the match patterns in the tests, which are for example used to check that the wsl shell wrapper scripts go to the correct distribution, so the debian and alpine pattern that just matched the name for all of them was little helpful
  • put the test user creation to the distribution just like in the production code instead of using failover fallback
  • restored testing of the default distribution that you changed to test an explicitly given one
  • test with debian-13 instead of debian where appropriate
  • changed the get...Condition methods to properly handle multiple distributions, that way you can also explicitly match the wanted alpine dists instead of a starts-with check
  • added the apt update retry to all debian distributions as the Debian servers are the ones which are unreliable, that should not be distribution specific
  • moved the deprecation warnings to be always be done, not only on refresh / update, those version-less dists should not be used at all anymore
  • changed the Alpine-17 wsl id to Alpine so that it really is a drop-in replacement down to the wsl id, except for the distribution-specific wsl shell wrapper, this will change then in the breaking release
  • reverted the cache key change, as far as I have seen what is cached under a given cache key did not change
  • changed the manual staging tactic by simply using cacheFile
  • guarded when case to simplify and deduplicate installer logic
  • removed the wsl.conf debug logging again, sorry. I think I did not do it because it is not well doable in a readable manner. wslOutput is not too suited for the end user.

@Vampire Vampire force-pushed the wsl-import branch 4 times, most recently from 0785097 to e7cc6c4 Compare April 9, 2026 22:30
@exoego
Copy link
Copy Markdown
Contributor Author

exoego commented Apr 10, 2026

Thanks!
All changes look good to me 👍

@Vampire Vampire added this to the Next Version milestone Apr 10, 2026
@Vampire Vampire merged commit a80ccdd into Vampire:master Apr 10, 2026
509 checks passed
@Vampire
Copy link
Copy Markdown
Owner

Vampire commented Apr 10, 2026

Oh, I claimed them for me accidentally.
Will fix that up and do a force-push.

@Vampire
Copy link
Copy Markdown
Owner

Vampire commented Apr 10, 2026

Done

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.

403 "Could not determine download URL" again for Alpine Out-dated link in sources.list in debian image

2 participants