Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
7d41e66
Add local registry, auth, and push image
kvega005 Apr 6, 2026
638ebfa
Fix test
kvega005 Apr 6, 2026
7fd4026
delete cleanup registry storage
kvega005 Apr 6, 2026
1fdb1b2
Do not use volume
kvega005 Apr 6, 2026
15d30b6
Merge remote-tracking branch 'origin/feature/wsl-for-apps' into user/…
kvega005 Apr 6, 2026
35e6322
Undo entry point fix (getting checked in seperately)
kvega005 Apr 6, 2026
b278c0a
undo entry point fix
kvega005 Apr 6, 2026
b988783
Fix formatting
kvega005 Apr 6, 2026
783ae7b
Address copilot comment
kvega005 Apr 6, 2026
ead90fc
Use packaged wslc-registry
kvega005 Apr 6, 2026
ce78d51
Merge branch 'feature/wsl-for-apps' into user/kevinve/registry
kvega005 Apr 7, 2026
5156db5
Address copilot comments
kvega005 Apr 7, 2026
31b5ad5
Address more copilot comments
kvega005 Apr 7, 2026
4cfd98c
Merge branch 'user/kevinve/registry' of https://github.com/kvega005/W…
kvega005 Apr 7, 2026
6305c58
Fix push and Pulll tests
kvega005 Apr 7, 2026
22cb648
Fix formatting
kvega005 Apr 7, 2026
3a0ba44
Merge branch 'feature/wsl-for-apps' into user/kevinve/registry
kvega005 Apr 7, 2026
83b39f2
Address suggestion
kvega005 Apr 7, 2026
a17819e
Address suggestions
kvega005 Apr 7, 2026
ba6c3de
Merge branch 'user/kevinve/registry' of https://github.com/kvega005/W…
kvega005 Apr 7, 2026
e329ac7
address suggestions
kvega005 Apr 7, 2026
868f69e
Merge branch 'feature/wsl-for-apps' into user/kevinve/registry
kvega005 Apr 7, 2026
3256f5d
Address copilot comments
kvega005 Apr 7, 2026
2d4dce9
Merge branch 'user/kevinve/registry' of https://github.com/kvega005/W…
kvega005 Apr 7, 2026
9177765
Remove wslc local registry
kvega005 Apr 7, 2026
0fa5505
formatting fix
kvega005 Apr 7, 2026
7b41634
Add script and docker file to generate test images.
kvega005 Apr 7, 2026
aaed20e
Address base64 encode feedback
kvega005 Apr 7, 2026
65aed10
Add Auth to SDK
kvega005 Apr 7, 2026
adab0ce
remove unneeded code
kvega005 Apr 7, 2026
3d0bad5
Address custom headers suggestion
kvega005 Apr 7, 2026
10491ee
Make regitsry auth required
kvega005 Apr 7, 2026
404a05e
Nit update script
kvega005 Apr 7, 2026
965f832
Merge branch 'feature/wsl-for-apps' into user/kevinve/registry
kvega005 Apr 7, 2026
2f35e77
Fix formatting
kvega005 Apr 8, 2026
71081bb
Update comment
kvega005 Apr 8, 2026
1734d51
Merge branch 'feature/wsl-for-apps' into user/kevinve/registry
kvega005 Apr 8, 2026
a40b27d
Fix tests
kvega005 Apr 8, 2026
bc989e5
Merge remote-tracking branch 'origin/feature/wsl-for-apps' into user/…
kvega005 Apr 8, 2026
7f59f8f
Merge branch 'feature/wsl-for-apps' into user/kevinve/registry
kvega005 Apr 8, 2026
d1455e0
Merge branch 'user/kevinve/registry' of https://github.com/kvega005/W…
kvega005 Apr 8, 2026
ef6f192
Fix tests
kvega005 Apr 8, 2026
d14cfec
Added back removed test + cleanup
kvega005 Apr 9, 2026
f4c1f39
Merge remote-tracking branch 'origin/feature/wsl-for-apps' into user/…
kvega005 Apr 9, 2026
c945517
Fix empty auth
kvega005 Apr 9, 2026
498588b
Merge branch 'feature/wsl-for-apps' into user/kevinve/registry
kvega005 Apr 9, 2026
baabcd9
Fix clang-format violations in test files
Apr 9, 2026
f6ea418
Merge remote-tracking branch 'origin/feature/wsl-for-apps' into user/…
kvega005 Apr 10, 2026
61dd8b4
Merge branch 'feature/wsl-for-apps' into user/kevinve/registry
kvega005 Apr 13, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,7 @@ set(COMMON_LINK_LIBRARIES
Shlwapi.lib
synchronization.lib
Bcrypt.lib
Crypt32.lib
icu.lib)

set(MSI_LINK_LIBRARIES
Expand Down
2 changes: 1 addition & 1 deletion packages.config
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<package id="Microsoft.WSL.DeviceHost" version="1.2.10-0" />
<package id="Microsoft.WSL.Kernel" version="6.6.114.1-1" targetFramework="native" />
<package id="Microsoft.WSL.LinuxSdk" version="1.20.0" targetFramework="native" />
<package id="Microsoft.WSL.TestData" version="0.3.0" />
<package id="Microsoft.WSL.TestData" version="0.4.0" />
<package id="Microsoft.WSL.TestDistro" version="2.7.1-1" />
<package id="Microsoft.WSLg" version="1.0.76" />
<package id="Microsoft.Xaml.Behaviors.WinUI.Managed" version="3.0.0" />
Expand Down
70 changes: 67 additions & 3 deletions src/windows/WslcSDK/wslcsdk.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -685,7 +685,6 @@ try
containerOptions.ContainerNetwork.ContainerNetworkType = internalContainerSettings->networking;

// TODO: No user access
// containerOptions.Entrypoint;
// containerOptions.Labels;
// containerOptions.LabelsCount;
// containerOptions.StopSignal;
Expand Down Expand Up @@ -1186,8 +1185,7 @@ try

auto progressCallback = ProgressCallback::CreateIf(options);

// TODO: Auth
return errorInfoWrapper.CaptureResult(internalType->session->PullImage(options->uri, nullptr, progressCallback.get()));
return errorInfoWrapper.CaptureResult(internalType->session->PullImage(options->uri, options->registryAuth, progressCallback.get()));
}
CATCH_RETURN();

Expand Down Expand Up @@ -1282,6 +1280,72 @@ try
}
CATCH_RETURN();

STDAPI WslcTagSessionImage(_In_ WslcSession session, _In_ const WslcTagImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage)
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

@JohnMcPMS to review the SDK changes

try
{
ErrorInfoWrapper errorInfoWrapper{errorMessage};
auto internalType = CheckAndGetInternalType(session);
RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType->session);
RETURN_HR_IF_NULL(E_POINTER, options);
RETURN_HR_IF_NULL(E_INVALIDARG, options->image);
RETURN_HR_IF_NULL(E_INVALIDARG, options->repo);
RETURN_HR_IF_NULL(E_INVALIDARG, options->tag);

WSLCTagImageOptions runtimeOptions{};
runtimeOptions.Image = options->image;
runtimeOptions.Repo = options->repo;
runtimeOptions.Tag = options->tag;

return errorInfoWrapper.CaptureResult(internalType->session->TagImage(&runtimeOptions));
}
CATCH_RETURN();

STDAPI WslcPushSessionImage(_In_ WslcSession session, _In_ const WslcPushImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage)
try
{
ErrorInfoWrapper errorInfoWrapper{errorMessage};
auto internalType = CheckAndGetInternalType(session);
RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType->session);
RETURN_HR_IF_NULL(E_POINTER, options);
RETURN_HR_IF_NULL(E_INVALIDARG, options->image);
RETURN_HR_IF_NULL(E_INVALIDARG, options->registryAuth);

auto progressCallback = ProgressCallback::CreateIf(options);

return errorInfoWrapper.CaptureResult(internalType->session->PushImage(options->image, options->registryAuth, progressCallback.get()));
}
CATCH_RETURN();

STDAPI WslcSessionAuthenticate(
_In_ WslcSession session,
_In_z_ PCSTR serverAddress,
_In_z_ PCSTR username,
_In_z_ PCSTR password,
_Outptr_result_z_ PSTR* identityToken,
_Outptr_opt_result_z_ PWSTR* errorMessage)
try
{
ErrorInfoWrapper errorInfoWrapper{errorMessage};
auto internalType = CheckAndGetInternalType(session);
RETURN_HR_IF_NULL(HRESULT_FROM_WIN32(ERROR_INVALID_STATE), internalType->session);
RETURN_HR_IF_NULL(E_POINTER, serverAddress);
RETURN_HR_IF_NULL(E_POINTER, username);
RETURN_HR_IF_NULL(E_POINTER, password);
RETURN_HR_IF_NULL(E_POINTER, identityToken);

*identityToken = nullptr;

wil::unique_cotaskmem_ansistring token;
auto hr = errorInfoWrapper.CaptureResult(internalType->session->Authenticate(serverAddress, username, password, &token));
if (SUCCEEDED(hr))
{
*identityToken = token.release();
}

return errorInfoWrapper;
}
CATCH_RETURN();

STDAPI WslcListSessionImages(_In_ WslcSession session, _Outptr_result_buffer_(*count) WslcImageInfo** images, _Out_ uint32_t* count)
try
{
Expand Down
3 changes: 3 additions & 0 deletions src/windows/WslcSDK/wslcsdk.def
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ WslcSetSessionSettingsTimeout
WslcSetSessionSettingsVhd

WslcTerminateSession
WslcSessionAuthenticate
WslcPullSessionImage
WslcImportSessionImage
WslcImportSessionImageFromFile
Expand All @@ -32,6 +33,8 @@ WslcDeleteSessionImage
WslcListSessionImages
WslcCreateSessionVhdVolume
WslcDeleteSessionVhdVolume
WslcTagSessionImage
WslcPushSessionImage

WslcSetContainerSettingsDomainName
WslcSetContainerSettingsName
Expand Down
59 changes: 53 additions & 6 deletions src/windows/WslcSDK/wslcsdk.h
Original file line number Diff line number Diff line change
Expand Up @@ -392,11 +392,6 @@ typedef struct WslcImageProgressMessage
_Out_ WslcImageProgressDetail detail;
} WslcImageProgressMessage;

typedef struct WslcRegistryAuthenticationInformation
{
// TBD
} WslcRegistryAuthenticationInformation;

// pointer-to-function typedef (unambiguous)
typedef HRESULT(CALLBACK* WslcContainerImageProgressCallback)(const WslcImageProgressMessage* progress, PVOID context);

Expand All @@ -406,7 +401,7 @@ typedef struct WslcPullImageOptions
_In_z_ PCSTR uri;
WslcContainerImageProgressCallback progressCallback;
PVOID progressCallbackContext;
_In_opt_ const WslcRegistryAuthenticationInformation* authInfo;
_In_opt_z_ PCSTR registryAuth;
} WslcPullImageOptions;

STDAPI WslcPullSessionImage(_In_ WslcSession session, _In_ const WslcPullImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);
Expand Down Expand Up @@ -457,6 +452,58 @@ typedef struct WslcImageInfo

STDAPI WslcDeleteSessionImage(_In_ WslcSession session, _In_z_ PCSTR nameOrId, _Outptr_opt_result_z_ PWSTR* errorMessage);

typedef struct WslcTagImageOptions
{
_In_z_ PCSTR image; // Source image name or ID.
_In_z_ PCSTR repo; // Target repository name.
_In_z_ PCSTR tag; // Target tag name.
} WslcTagImageOptions;

STDAPI WslcTagSessionImage(_In_ WslcSession session, _In_ const WslcTagImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);

typedef struct WslcPushImageOptions
{
_In_z_ PCSTR image;
_In_z_ PCSTR registryAuth; // Base64-encoded X-Registry-Auth header value.
_In_opt_ WslcContainerImageProgressCallback progressCallback;
_In_opt_ PVOID progressCallbackContext;
} WslcPushImageOptions;

STDAPI WslcPushSessionImage(_In_ WslcSession session, _In_ const WslcPushImageOptions* options, _Outptr_opt_result_z_ PWSTR* errorMessage);

// Authenticates with a container registry and returns an identity token.
//
// Parameters:
// session
// A valid WslcSession handle.
//
// serverAddress
// The registry server address (e.g. "127.0.0.1:5000").
//
// username
// The username for authentication.
//
// password
// The password for authentication.
//
// identityToken
// On success, receives a pointer to a null-terminated ANSI string
// containing the identity token.
//
// The string is allocated using CoTaskMemAlloc. The caller takes
// ownership of the returned memory and must free it by calling
// CoTaskMemFree when it is no longer needed.
//
// Return Value:
// S_OK on success. Otherwise, an HRESULT error code indicating the failure.
STDAPI WslcSessionAuthenticate(
_In_ WslcSession session,
_In_z_ PCSTR serverAddress,
_In_z_ PCSTR username,
_In_z_ PCSTR password,
_Outptr_result_z_ PSTR* identityToken,
_Outptr_opt_result_z_ PWSTR* errorMessage);

// Retrieves the list of container images
// Parameters:
// session
Expand Down
2 changes: 2 additions & 0 deletions src/windows/common/WSLCContainerLauncher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ Module Name:
This file contains the implementation for WSLCContainerLauncher.
--*/

#include "precomp.h"
#include "WSLCContainerLauncher.h"

using wsl::windows::common::ClientRunningWSLCProcess;
Expand Down
1 change: 1 addition & 0 deletions src/windows/common/WSLCContainerLauncher.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class WSLCContainerLauncher : private WSLCProcessLauncher
void SetDnsSearchDomains(std::vector<std::string>&& DnsSearchDomains);
void SetDnsOptions(std::vector<std::string>&& DnsOptions);

using WSLCProcessLauncher::FormatResult;
using WSLCProcessLauncher::SetUser;
using WSLCProcessLauncher::SetWorkingDirectory;

Expand Down
46 changes: 46 additions & 0 deletions src/windows/common/wslutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Module Name:
#include "precomp.h"
#include "wslutil.h"
#include "WslPluginApi.h"
#include <wincrypt.h>
#include "wslinstallerservice.h"
#include "wslc.h"

Expand Down Expand Up @@ -1422,4 +1423,49 @@ catch (...)
{
LOG_CAUGHT_EXCEPTION();
return nullptr;
}

std::string wsl::windows::common::wslutil::Base64Encode(const std::string& input)
{
DWORD base64Size = 0;
THROW_IF_WIN32_BOOL_FALSE(CryptBinaryToStringA(
reinterpret_cast<const BYTE*>(input.c_str()), static_cast<DWORD>(input.size()), CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF, nullptr, &base64Size));

auto buffer = std::make_unique<char[]>(base64Size);
THROW_IF_WIN32_BOOL_FALSE(CryptBinaryToStringA(
reinterpret_cast<const BYTE*>(input.c_str()),
static_cast<DWORD>(input.size()),
CRYPT_STRING_BASE64 | CRYPT_STRING_NOCRLF,
buffer.get(),
&base64Size));

return std::string(buffer.get());
}

std::string wsl::windows::common::wslutil::Base64Decode(const std::string& encoded)
{
DWORD size = 0;
THROW_IF_WIN32_BOOL_FALSE(CryptStringToBinaryA(
encoded.c_str(), static_cast<DWORD>(encoded.size()), CRYPT_STRING_BASE64, nullptr, &size, nullptr, nullptr));

std::string result(size, '\0');
THROW_IF_WIN32_BOOL_FALSE(CryptStringToBinaryA(
encoded.c_str(), static_cast<DWORD>(encoded.size()), CRYPT_STRING_BASE64, reinterpret_cast<BYTE*>(result.data()), &size, nullptr, nullptr));

result.resize(size);
return result;
}

std::string wsl::windows::common::wslutil::BuildRegistryAuthHeader(const std::string& username, const std::string& password, const std::string& serverAddress)
{
nlohmann::json authJson = {{"username", username}, {"password", password}, {"serveraddress", serverAddress}};

return Base64Encode(authJson.dump());
}

std::string wsl::windows::common::wslutil::BuildRegistryAuthHeader(const std::string& identityToken, const std::string& serverAddress)
{
nlohmann::json authJson = {{"identitytoken", identityToken}, {"serveraddress", serverAddress}};

return Base64Encode(authJson.dump());
}
11 changes: 11 additions & 0 deletions src/windows/common/wslutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -330,4 +330,15 @@ WSLCHandle ToCOMInputHandle(HANDLE Handle);

winrt::Windows::Management::Deployment::PackageVolume GetSystemVolume();

std::string Base64Encode(const std::string& input);
std::string Base64Decode(const std::string& encoded);

// Builds the base64-encoded X-Registry-Auth header value used by Docker APIs
// (PullImage, PushImage, etc.) from the given credentials.
std::string BuildRegistryAuthHeader(const std::string& username, const std::string& password, const std::string& serverAddress);

// Builds the base64-encoded X-Registry-Auth header value from an identity token
// returned by Authenticate().
std::string BuildRegistryAuthHeader(const std::string& identityToken, const std::string& serverAddress);

} // namespace wsl::windows::common::wslutil
19 changes: 19 additions & 0 deletions src/windows/inc/docker_schema.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,25 @@ struct EmptyRequest
using TResponse = void;
};

struct AuthRequest
{
using TResponse = struct AuthResponse;

std::string username;
std::string password;
std::string serveraddress;

NLOHMANN_DEFINE_TYPE_INTRUSIVE(AuthRequest, username, password, serveraddress);
};

struct AuthResponse
{
std::string Status;
std::optional<std::string> IdentityToken;

NLOHMANN_DEFINE_TYPE_INTRUSIVE_WITH_DEFAULT(AuthResponse, Status, IdentityToken);
};

struct CreateVolume
{
using TResponse = void;
Expand Down
3 changes: 3 additions & 0 deletions src/windows/service/inc/wslc.idl
Original file line number Diff line number Diff line change
Expand Up @@ -677,6 +677,9 @@ interface IWSLCSession : IUnknown
HRESULT DeleteVolume([in] LPCSTR Name);
HRESULT ListVolumes([out, size_is(, *Count)] WSLCVolumeInformation** Volumes, [out] ULONG* Count);
HRESULT InspectVolume([in] LPCSTR Name, [out] LPSTR* Output);

HRESULT Authenticate([in] LPCSTR ServerAddress, [in] LPCSTR Username, [in] LPCSTR Password, [out] LPSTR* IdentityToken);
HRESULT PushImage([in] LPCSTR Image, [in] LPCSTR RegistryAuthenticationInformation, [in, unique] IProgressCallback* ProgressCallback);
}

//
Expand Down
Loading