Skip to content

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

Open
exoego wants to merge 27 commits intoVampire:masterfrom
exoego:wsl-import
Open

feat: Add versioned distributions, replace non-versioned Alpine and Debian with wsl --import#85
exoego wants to merge 27 commits intoVampire:masterfrom
exoego:wsl-import

Conversation

@exoego
Copy link
Copy Markdown

@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).

exoego added 4 commits April 4, 2026 09:15
Replace the stale aka.ms shortlink for Debian (which still served Debian 11 bullseye with broken backports repositories) with the Debian 13 trixie .wsl file from Salsa.

Replace the Microsoft Store download for Alpine (which relied on a third-party API that now blocks automated usage) with the official Alpine minirootfs tarball.

Both distributions are now installed via wsl --import instead of the AppxBundle installer.

Fixes Vampire#76, fixes Vampire#82
Use a staging directory on the same drive as the download before calling cacheDir(), which handles cross-device moves properly.

The direct mv() from D: (RUNNER_TEMP) to C: (tool cache) failed with EXDEV on Windows runners.
Debian 13 (trixie) ships with a default /etc/wsl.conf, similar to Ubuntu-24.04.
Alpine minirootfs lacks shadow utilities (useradd), so fall back to BusyBox adduser when useradd is not available.
@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 added 11 commits April 5, 2026 07:55
The third-party API at store.rg-adguard.net, which was used to resolve Microsoft Store download URLs, has permanently blocked automated usage.
Remove all related code: productId constructors, dynamic URL resolution via HTTP client, echo endpoint debug logic, and Ktor imports.

All distributions now use direct download URLs.
Replace the useWslImport boolean with an InstallMethod enum derived from the installer file extension: .exe for AppxBundle, .wsl for wsl --install --from-file (with --import fallback on older WSL), and .tar.gz for wsl --import.
Add open createUser() method to Distribution with useradd as default.
Override in ApkBasedDistribution to use BusyBox adduser instead.
This replaces the try-useradd-then-fallback-to-adduser approach with a direct call to the correct command for each distribution.
Keep "Debian" pointing to the old bullseye AppxBundle for backward compatibility
but emit a deprecation warning. Register "Debian-11" as an alias.
Add "Debian-12" (bookworm) and "Debian-13" (trixie) using .wsl files from Salsa, installed via wsl --install --from-file with --import fallback.
Remove the old "Alpine" distribution which relied on a third-party Microsoft Store API that has permanently blocked automated usage.
Add versioned distributions (Alpine-3.20, Alpine-3.21, Alpine-3.22, Alpine-3.23) using official minirootfs tarballs installed via wsl --import.
Some distributions (Debian-13, Ubuntu-24.04) ship with a default /etc/wsl.conf.
Log existing contents in debug mode before overwriting, document the overwrite behavior in action.yml, and update the test to accept known default content instead of suppressing per-distribution.
Use useradd-or-adduser fallback in test user creation for Alpine compatibility.
Install bash dynamically for Alpine distributions in the wsl-bash scripts test instead of using a hardcoded index.
The old Debian distribution (bullseye) is deprecated and its apt-get update fails due to removed backports repositories.
Debian-13 (trixie) is the appropriate new default.
Remove deprecated Debian (bullseye) from the distributions test matrix since its apt-get update fails due to removed backports.
Debian-12 and Debian-13 provide full Debian test coverage.
Update test_multiple_usage_with_same_distribution to use Debian-13 as the secondary distribution.
wsl --install --from-file prompts for interactive UNIX user creation which hangs in CI environments. Use wsl --import for both .wsl and .tar.gz files since it imports directly as root without prompts.
installerFile is only needed for AppxBundle distributions to locate the .exe inside the extracted archive.
For .wsl and .tar.gz distributions the filename is derived from the download URL via downloadFileName, removing redundant configuration.
@exoego
Copy link
Copy Markdown
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 added 5 commits April 6, 2026 08:50
Debian-11 is now its own object with a separate wslId ("Debian-11") rather than an alias for the unversioned "Debian".
Use --no-launch to skip the OOBE script that prompts for interactive user creation, keeping root as the default user.
This properly uses the intended installation command for .wsl files while remaining compatible with CI environments.
The last Alpine version that worked via the Microsoft Store was 3.17.
Restore "Alpine" as a deprecated distribution pointing to 3.17 (same pattern as "Debian").
Add Alpine-3.17, Alpine-3.18, and Alpine-3.19 using official minirootfs tarballs.
The adduser override was on ApkBasedDistribution, but other future apk-based distributions may have the shadow package and support useradd.
Introduce AlpineDistribution as an intermediate subclass that overrides createUser to use BusyBox adduser, keeping ApkBasedDistribution generic.
The wsl.conf tests now use diff to verify the file content matches what the action wrote, instead of only checking that the file exists.
exoego added 7 commits April 6, 2026 09:10
Ktor was only used for the rg-adguard API calls which have been removed. The distribution downloads use @actions/tool-cache downloadTool() instead.
Remove the Ktor client dependencies, version catalog entries, and the build script workaround that patched abort-controller and node-fetch requires.
Older WSL versions (e.g. on windows-2022) do not support --from-file. Check wslHelp() and fall back to wsl --import for .wsl files on those environments.
Debian-11 is the same bullseye image as the old "Debian" default, preserving compatibility for users who rely on the default without specifying a distribution explicitly.
The AppxBundle installer registers the distribution as "Debian", not "Debian-11".
The wslId must match the registered name for wsl --set-default and other WSL commands to work.
The default distribution test uses update=true, which fails on Debian-11 due to the broken bullseye-backports repository.
Use Debian-13 for this test since it exercises the update flow with a working distribution.
The cached filename changed from installerFile to downloadFileName,
so stale caches from previous runs contain files under the old name.
Bump the cache key prefix from 2 to 3 to force re-download.
@exoego exoego marked this pull request as draft April 6, 2026 11:36
@exoego
Copy link
Copy Markdown
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
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