Skip to content

Comments

Followup changes to address todos in delete and list#14189

Draft
yao-msft wants to merge 13 commits intofeature/wsl-for-appsfrom
user/yaosun/todolistdelete
Draft

Followup changes to address todos in delete and list#14189
yao-msft wants to merge 13 commits intofeature/wsl-for-appsfrom
user/yaosun/todolistdelete

Conversation

@yao-msft
Copy link

@yao-msft yao-msft commented Feb 9, 2026

Summary of the Pull Request

Followup changes to address todos in delete and list

PR Checklist

  • Closes: Link to issue #xxx
  • Communication: I've discussed this with core contributors already. If work hasn't been agreed, this work might be rejected
  • Tests: Added/updated if needed and all pass
  • Localization: All end user facing strings can be localized
  • Dev docs: Added/updated if needed
  • Documentation updated: If checked, please file a pull request on our docs repo and link it here: #xxx

Detailed Description of the Pull Request / Additional comments

Validation Steps Performed

Added more tests.

@yao-msft yao-msft requested a review from a team as a code owner February 9, 2026 20:55
Copilot AI review requested due to automatic review settings February 9, 2026 20:55
@yao-msft yao-msft marked this pull request as draft February 9, 2026 20:57
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Updates the WSLA image list/delete surface area by expanding ListImages to accept filter options and returning additional image metadata, while shifting DeleteImage to a flags-based options model; corresponding Docker API plumbing and Windows tests are updated to match.

Changes:

  • Extend IWSLASession::ListImages with options (filters/flags) and WSLA_IMAGE_INFORMATION with digest/created/parent metadata.
  • Replace WSLA_DELETE_IMAGE_OPTIONS boolean fields with a Flags bitfield and update DeleteImage handling.
  • Add/expand WSLA tests to cover list filtering and new image metadata fields.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
test/windows/WSLATests.cpp Updates ListImages/DeleteImage usage and adds broader ListImages test coverage (filters/flags/fields).
src/windows/wslaservice/inc/wslaservice.idl Updates COM IDL types and ListImages signature; introduces new flags/options structs.
src/windows/wslaservice/exe/WSLASession.h Updates WSLASession::ListImages method signature to match IDL.
src/windows/wslaservice/exe/WSLASession.cpp Implements ListImages options/filters, populates new fields, and updates DeleteImage to use flags.
src/windows/wslaservice/exe/DockerHTTPClient.h Adds ListImages filter struct and expands ListImages API to accept flags/filters.
src/windows/wslaservice/exe/DockerHTTPClient.cpp Builds Docker /images/json query parameters + JSON filters for ListImages.
src/windows/inc/docker_schema.h Extends Docker image schema parsing to include digests/created/parent id.


HRESULT WSLASession::ListImages(const WSLA_LIST_IMAGES_OPTIONS* Options, WSLA_IMAGE_INFORMATION** Images, ULONG* Count, WSLA_ERROR_INFO* Error)
try
{
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

ListImages dereferences Count and Images immediately (*Count = 0; *Images = nullptr;) but does not validate they are non-null. Other COM methods in this file (e.g. DeleteImage) return E_POINTER for null out-params; ListImages should do the same to avoid potential AVs in the service when called incorrectly.

Suggested change
{
{
if (Images == nullptr || Count == nullptr)
{
return E_POINTER;
}

Copilot uses AI. Check for mistakes.
Comment on lines +719 to +727
if ((e.StatusCode() >= 400 && e.StatusCode() < 500))
{
errorMessage = e.DockerMessage<docker_schema::ErrorResponse>().message;
if (Error != nullptr)
{
Error->UserErrorMessage = wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(errorMessage.c_str()).release();
}
}

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

In the DockerHTTPException handler, errorMessage is only populated for 4xx responses; for 5xx/other failures this throws E_FAIL with an empty message and leaves ErrorInfo unset. Populate a meaningful message for non-4xx cases (e.g., from the response body / exception details) so callers get actionable diagnostics.

Suggested change
if ((e.StatusCode() >= 400 && e.StatusCode() < 500))
{
errorMessage = e.DockerMessage<docker_schema::ErrorResponse>().message;
if (Error != nullptr)
{
Error->UserErrorMessage = wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(errorMessage.c_str()).release();
}
}
// First, try to extract a Docker error response message, regardless of status code.
try
{
const auto dockerError = e.DockerMessage<docker_schema::ErrorResponse>();
if (!dockerError.message.empty())
{
errorMessage = dockerError.message;
}
}
catch (...)
{
// If we cannot parse a Docker error message, fall back to a generic one below.
}
// If we still do not have a message, construct a generic one with the status code.
if (errorMessage.empty())
{
errorMessage = wil::str_printf<std::string>(
"Docker API request failed with status code %u.", e.StatusCode());
}
if (Error != nullptr && !errorMessage.empty())
{
Error->UserErrorMessage =
wil::make_unique_ansistring<wil::unique_cotaskmem_ansistring>(errorMessage.c_str()).release();
}

Copilot uses AI. Check for mistakes.
Comment on lines +784 to +803
// Extract repo name from tag (format: "repo:tag")
// and lookup corresponding digest from the map
size_t colonPos = tag.find(':');
if (colonPos != std::string::npos && colonPos > 0)
{
std::string repoName = tag.substr(0, colonPos);
auto it = repoToDigest.find(repoName);
if (it != repoToDigest.end())
{
THROW_HR_IF(E_UNEXPECTED, strcpy_s(output[index].Digest, it->second.c_str()) != 0);
}
else
{
output[index].Digest[0] = '\0';
}
}
else
{
output[index].Digest[0] = '\0';
}
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

Digest lookup extracts the repo name from a tag by using tag.find(':'), which breaks for image references containing a registry port (e.g. localhost:5000/repo:tag): the repo becomes localhost and won’t match RepoDigests entries. Parse the tag using the last : that appears after the last / (Docker tag separator rules) before looking up the digest.

Copilot uses AI. Check for mistakes.
Comment on lines +562 to +566
options.Before = nullptr;
options.Since = debianId.c_str();
options.Labels = nullptr;
options.LabelsCount = 0;

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

Indentation looks off for options.LabelsCount = 0; in this block, which hurts readability and makes it easy to miss the assignment. Please align it with the surrounding options.* assignments.

Copilot uses AI. Check for mistakes.
Comment on lines +576 to +581
options.Reference = nullptr;
options.Before = alpineId.c_str();
options.Since = nullptr;
options.Labels = nullptr;
options.LabelsCount = 0;

Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

Indentation looks off for options.LabelsCount = 0; in this block as well. Please reformat so the assignment is aligned with the other options.* lines.

Copilot uses AI. Check for mistakes.
HRESULT ImportImage([in] ULONG ImageHandle, [in] LPCSTR ImageName, [in, unique] IProgressCallback* ProgressCallback, [in] ULONGLONG ContentLength);
HRESULT SaveImage([in] ULONG OutputHandle, [in] LPCSTR ImageNameOrID, [in, unique] IProgressCallback * ProgressCallback, [in, out, unique] WSLA_ERROR_INFO * ErrorInfo);
HRESULT ListImages([out, size_is(, *Count)] struct WSLA_IMAGE_INFORMATION** Images, [out] ULONG* Count);
HRESULT ListImages([in, unique] const struct WSLA_LIST_IMAGES_OPTIONS* Options, [out, size_is(, *Count)] struct WSLA_IMAGE_INFORMATION** Images, [out] ULONG* Count, [in, out, unique] WSLA_ERROR_INFO* ErrorInfo);
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

Changing the signature of an existing COM interface method (IWSLASession::ListImages) without changing the interface IID breaks COM binary compatibility: older clients can end up calling the wrong vtable slot/with the wrong arguments. Consider introducing a new interface (e.g. IWSLASession2 with a new UUID) or adding a new method while keeping the old ListImages contract intact.

Suggested change
HRESULT ListImages([in, unique] const struct WSLA_LIST_IMAGES_OPTIONS* Options, [out, size_is(, *Count)] struct WSLA_IMAGE_INFORMATION** Images, [out] ULONG* Count, [in, out, unique] WSLA_ERROR_INFO* ErrorInfo);
HRESULT ListImages([in, unique] const struct WSLA_LIST_IMAGES_OPTIONS* Options, [out, size_is(, *Count)] struct WSLA_IMAGE_INFORMATION** Images, [out] ULONG* Count);
HRESULT ListImages2([in, unique] const struct WSLA_LIST_IMAGES_OPTIONS* Options, [out, size_is(, *Count)] struct WSLA_IMAGE_INFORMATION** Images, [out] ULONG* Count, [in, out, unique] WSLA_ERROR_INFO* ErrorInfo);

Copilot uses AI. Check for mistakes.
char Image[WSLA_MAX_IMAGE_NAME_LENGTH + 1];
char Hash[256];
char Digest[256];
ULONGLONG Size;
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

WSLA_IMAGE_INFORMATION layout changed (new fields, removed DownloadTimestamp). For COM marshaling/binary consumers, changing an existing struct used in an interface method is a breaking ABI change. If compatibility matters, consider defining a new struct (e.g. WSLA_IMAGE_INFORMATION_V2) and returning that from a new method/interface.

Suggested change
ULONGLONG Size;
ULONGLONG Size;
LONGLONG DownloadTimestamp; // Unix timestamp when the image was downloaded (retained for ABI compatibility)

Copilot uses AI. Check for mistakes.
Comment on lines 401 to 405
struct WSLA_DELETE_IMAGE_OPTIONS
{
LPCSTR Image; // Image can be ID or Repo:Tag.
BOOL Force;
BOOL NoPrune;
DWORD Flags; // WSLADeleteImageFlags
// TODO: Platforms: a json array of OCI platform strings.
Copy link

Copilot AI Feb 9, 2026

Choose a reason for hiding this comment

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

WSLA_DELETE_IMAGE_OPTIONS changed from two BOOL fields to a Flags DWORD. As with other COM structs, changing the layout of an existing options struct is a breaking change for any client compiled against the old IDL. If backward compatibility is required, keep the old struct and add a new *_V2 struct or new method.

Copilot uses AI. Check for mistakes.
WSLAListImagesFlagsNone = 0,
WSLAListImagesFlagsAll = 1, // Show all images (default hides intermediate images)
WSLAListImagesFlagsDigests = 2, // Include digest information
WSLAListImagesFlagsDanglingTrue = 4, // Show only dangling images (untagged)
Copy link
Collaborator

Choose a reason for hiding this comment

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

nit: We could simplify this a bit by having:

WSLAListImagesFlagsShowDangling,
WSLAListImagesFlagsShowNonDangling,

And having the caller set those by default, that way we don't have to do any special logic for it in the service

Copy link
Author

Choose a reason for hiding this comment

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

Is this comment just about renaming the flag?

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.

2 participants