Skip to content

[confcom] C-WCOW support#9776

Closed
micromaomao wants to merge 23 commits intoAzure:mainfrom
micromaomao:tingmao/windows-platform-support
Closed

[confcom] C-WCOW support#9776
micromaomao wants to merge 23 commits intoAzure:mainfrom
micromaomao:tingmao/windows-platform-support

Conversation

@micromaomao
Copy link
Copy Markdown
Member

@micromaomao micromaomao commented Apr 13, 2026

Add support for generating C-WCOW (Windows confidential containers) policies.


This checklist is used to make sure that common guidelines for a pull request are followed.

Related command

General Guidelines

  • Have you run azdev style <YOUR_EXT> locally? (pip install azdev required)
  • Have you run python scripts/ci/test_index.py -q locally? (pip install wheel==0.30.0 required)
  • My extension version conforms to the Extension version schema

For new extensions:

About Extension Publish

There is a pipeline to automatically build, upload and publish extension wheels.
Once your pull request is merged into main branch, a new pull request will be created to update src/index.json automatically.
You only need to update the version information in file setup.py and historical information in file HISTORY.rst in your PR but do not modify src/index.json.

@azure-client-tools-bot-prd
Copy link
Copy Markdown

azure-client-tools-bot-prd bot commented Apr 13, 2026

️✔️Azure CLI Extensions Breaking Change Test
️✔️Non Breaking Changes

@yonzhan
Copy link
Copy Markdown
Collaborator

yonzhan commented Apr 13, 2026

Thank you for your contribution! We will review the pull request and get back to you soon.

@github-actions
Copy link
Copy Markdown
Contributor

The git hooks are available for azure-cli and azure-cli-extensions repos. They could help you run required checks before creating the PR.

Please sync the latest code with latest dev branch (for azure-cli) or main branch (for azure-cli-extensions).
After that please run the following commands to enable git hooks:

pip install azdev --upgrade
azdev setup -c <your azure-cli repo path> -r <your azure-cli-extensions repo path>

@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Apr 13, 2026

Hi @micromaomao

⚠️ Release Requirements

Module: confcom

  • ⚠️ Please update VERSION to be 1.8.1 in src/confcom/setup.py
  • ⚠️ Remove azext.isPreview: true in azext_metadata.json for confcom

Notes

@github-actions github-actions bot added the release-version-block Updates do not qualify release version rules. NOTE: please do not edit it manually. label Apr 13, 2026
@micromaomao micromaomao force-pushed the tingmao/windows-platform-support branch from 51ea85c to e4d1736 Compare April 13, 2026 10:33
@micromaomao micromaomao force-pushed the tingmao/windows-platform-support branch from e4d1736 to 631c766 Compare April 13, 2026 11:29
@micromaomao micromaomao marked this pull request as ready for review April 14, 2026 00:25
Copilot AI review requested due to automatic review settings April 14, 2026 00:25
@micromaomao
Copy link
Copy Markdown
Member Author

micromaomao commented Apr 14, 2026

@yonzhan @necusjz How do we properly set the next version to 2.0.0b1? The pipeline insists that it has to be 1.8.1 for some reason: #9776 (comment)

Copy link
Copy Markdown
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

This PR adds support in the confcom extension for generating policies for C-WCOW (Windows confidential containers), extending the existing Linux policy generation flow with Windows-specific policy fields, hashing outputs, and Rego boilerplate.

Changes:

  • Add Windows platform detection and propagate per-image platform through policy generation, hashing, and policy serialization.
  • Extend hashing/layer metadata handling to support Windows CIM-based hashing output (mounted_cim) and update dmverity-vhd binary version.
  • Introduce Windows-specific debug-mode settings and a Windows Rego policy template; bump API/version metadata for the extension.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
src/confcom/setup.py Bumps extension version to 2.0.0b1.
src/confcom/azext_confcom/tests/latest/test_confcom_containers_from_image.py Updates test call signature for containers_from_image.
src/confcom/azext_confcom/template_util.py Adds platform into image info and attempts platform-aware pulls.
src/confcom/azext_confcom/security_policy.py Tracks single platform per policy, selects Linux vs Windows Rego boilerplate, and passes platform into hashing.
src/confcom/azext_confcom/rootfs_proxy.py Updates dmverity-vhd version and switches hashing output parsing to JSON with optional mounted_cim.
src/confcom/azext_confcom/lib/policy.py Bumps policy API version to 0.11.0.
src/confcom/azext_confcom/lib/images.py Adds platform-aware pull logic and exposes get_image_platform; adds platform parameter to layer hashing.
src/confcom/azext_confcom/lib/defaults.py Adds helper to pick Linux vs Windows debug execProcesses.
src/confcom/azext_confcom/lib/containers.py Adds platform to container definitions derived from images and hashes layers for that platform.
src/confcom/azext_confcom/data/internal_config.json Bumps API version and adds Windows debug-mode configuration.
src/confcom/azext_confcom/data/customer_rego_policy_windows.txt Adds Windows-specific customer policy boilerplate.
src/confcom/azext_confcom/data/customer_rego_policy.txt Adds rw_mount_device framework binding.
src/confcom/azext_confcom/data/README Adds a note about data files (currently inconsistent with actual usage).
src/confcom/azext_confcom/custom.py Updates _containers_from_image invocation parameter name.
src/confcom/azext_confcom/container.py Adds platform/mounted_cim fields and Windows-specific policy element differences.
src/confcom/azext_confcom/config.py Adds config wiring for Windows debug mode and Windows Rego template file.
src/confcom/azext_confcom/command/containers_from_vn2.py Updates container_from_image invocation parameter name.
src/confcom/azext_confcom/command/containers_from_image.py Renames function parameter to aci_or_vn2.
src/confcom/azext_confcom/azext_metadata.json Marks the extension as preview.
src/confcom/azext_confcom/_help.py Clarifies that --platform must be aci or vn2 for containers from_image.
src/confcom/README.md Documents Windows-only CIM dependency expectations.
src/confcom/HISTORY.rst Adds release notes for 2.0.0b1 (formatting currently incorrect).
Comments suppressed due to low confidence (2)

src/confcom/azext_confcom/container.py:829

  • env_rules is set to dict() for non-Linux, but the code later does env_rules += _INJECTED_SERVICE_VN2_ENV_RULES and passes it to set_extra_environment_rules, both of which expect a list. This will raise at runtime for Windows containers. Initialize env_rules as an empty list instead (and keep the list type consistent across branches).
        # Start with the customer environment rules
        env_rules = copy.deepcopy(_INJECTED_CUSTOMER_ENV_RULES) if container_json["platform"].startswith("linux") else dict()
        # If is_vn2, add the VN2 environment rules
        if is_vn2:
            env_rules += _INJECTED_SERVICE_VN2_ENV_RULES
            image.set_mounts(image.get_mounts() + copy.deepcopy(config.DEFAULT_MOUNTS_VIRTUAL_NODE))

src/confcom/azext_confcom/rootfs_proxy.py:100

  • layer_cache is keyed only by image:tag, but the returned content now depends on platform (and potentially tar_location / faster_hashing). This can return incorrect cached results when the same image is hashed for different platforms/options in the same process. Include platform (and other inputs that affect output) in the cache key.
        image_name = f"{image}:{tag}"
        # populate layer info
        if self.layer_cache.get(image_name):
            return self.layer_cache.get(image_name)

Comment on lines +22 to +33
@functools.lru_cache()
def pull_image(image_reference: str) -> docker.models.images.Image:
client = docker.from_env()

for platform in SUPPORTED_PLATFORMS:
try:
image = client.images.pull(image_reference, platform=platform)
return image
except (docker.errors.ImageNotFound, docker.errors.NotFound):
continue

raise ValueError(f"Image '{image_reference}' not found for any supported platform: {SUPPORTED_PLATFORMS}")
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

pull_image() always uses client.images.pull(...) and never checks client.images.get(...) first. This breaks local-only images (e.g., tests build confcom_test_* locally) because platform detection will attempt a remote pull and fail even though the image exists locally. Consider trying images.get(image_reference) first (and only pulling when not present), or have get_image_platform() use get_image() to support local images.

Copilot uses AI. Check for mistakes.
mounts=mounts,
allow_elevated=allow_elevated,
extraEnvironmentRules=[],
platform=container_json["platform"],
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

ContainerImage.from_json now requires container_json["platform"], which will raise a KeyError for older inputs (e.g., previously generated JSON/policies without a platform field). Use a default such as container_json.get("platform", "linux/amd64") (and similarly for other direct indexing) to preserve backward compatibility.

Suggested change
platform=container_json["platform"],
platform=container_json.get("platform", "linux/amd64"),

Copilot uses AI. Check for mistakes.
Comment on lines +155 to +164
for platform in ["linux/amd64", "windows/amd64"]:
try:
raw_image = client.images.pull(image_name, platform=platform)
break
except (docker.errors.ImageNotFound, docker.errors.NotFound):
continue
image_info = {
"platform": "/".join([raw_image.attrs.get("Os"), raw_image.attrs.get("Architecture")]),
**raw_image.attrs.get("Config")
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

If pulling the image fails for all attempted platforms, raw_image remains None and the subsequent raw_image.attrs... access will raise an AttributeError. After the pull loop, explicitly handle the “not found for any supported platform” case (e.g., raise/print an error) before building image_info.

Copilot uses AI. Check for mistakes.
pretty_print_func(self._allow_runtime_logging),
pretty_print_func(self._allow_environment_variable_dropping),
)

Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

_add_rego_boilerplate has no final else/error for unsupported platforms, so it can return None and break callers expecting a string. Add an explicit error/exception when self._platform is not a recognized linux/* or windows/* value.

Suggested change
raise ValueError(f"Unsupported platform for rego boilerplate generation: {self._platform}")

Copilot uses AI. Check for mistakes.
Comment on lines +819 to +821
# Use platform from template if specified, otherwise try to auto-detect from image
platform = case_insensitive_dict_get(image_properties, "platform")
if not platform:
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

Platform auto-detection here calls get_image_platform(image_name), which pulls images via Docker. This introduces a hard Docker dependency even for the “tarball / clean-room” flow where get_image_info can read image metadata from a tar without Docker running. Consider deferring platform resolution until after get_image_info (or deriving it from the tar metadata) so tar-only usage doesn’t regress.

Suggested change
# Use platform from template if specified, otherwise try to auto-detect from image
platform = case_insensitive_dict_get(image_properties, "platform")
if not platform:
# Use platform from template if specified. Otherwise, prefer image metadata
# so tarball-based flows do not require Docker for platform detection.
platform = case_insensitive_dict_get(image_properties, "platform")
if not platform:
image_info = get_image_info(image_name)
if isinstance(image_info, dict):
platform = case_insensitive_dict_get(image_info, "platform")
if not platform:
image_os = case_insensitive_dict_get(image_info, "os")
image_architecture = case_insensitive_dict_get(image_info, "architecture")
if image_os and image_architecture:
platform = f"{image_os}/{image_architecture}"
else:
platform = getattr(image_info, "platform", None)
if not platform:
image_os = getattr(image_info, "os", None)
image_architecture = getattr(image_info, "architecture", None)
if image_os and image_architecture:
platform = f"{image_os}/{image_architecture}"
if not platform:

Copilot uses AI. Check for mistakes.
Comment on lines +133 to +136
image_info = {
"platform": "/".join([raw_image.attrs.get("Os"), raw_image.attrs.get("Architecture")]),
**raw_image.attrs.get("Config")
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

get_image_info builds image_info via {..., **raw_image.attrs.get("Config")}. If Config is missing/None, this will throw a TypeError. Safer is config = raw_image.attrs.get("Config") or {} (and then splat that), so the function doesn’t crash on unexpected image metadata.

Copilot uses AI. Check for mistakes.
Comment on lines +151 to +152
else:
assert self._platform == image_platform, "All images must have the same platform"
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

Using assert for user-facing validation (All images must have the same platform) is unsafe because assertions can be disabled with Python optimizations (-O). Replace the assert with a normal exception (e.g., ValueError) or an eprint(...) + exit path so the check is always enforced.

Suggested change
else:
assert self._platform == image_platform, "All images must have the same platform"
elif self._platform != image_platform:
raise ValueError("All images must have the same platform")

Copilot uses AI. Check for mistakes.
Comment thread src/confcom/azext_confcom/data/README Outdated
@@ -0,0 +1 @@
internal_config.json and customer_rego_policy.txt are obsolete versions to be removed, new work should happen in src/confcom/azext_confcom/lib/policy.py
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

The new note claims internal_config.json and customer_rego_policy.txt are obsolete, but both are still actively loaded/used by config.py (e.g., CONFIG_FILE = ./data/internal_config.json, CUSTOMER_REGO_POLICY = load_str_from_file(...)). This documentation is currently incorrect and will mislead future maintenance; update it to reflect the current source of truth.

Suggested change
internal_config.json and customer_rego_policy.txt are obsolete versions to be removed, new work should happen in src/confcom/azext_confcom/lib/policy.py
internal_config.json and customer_rego_policy.txt are still used by the current configuration/runtime path (for example via config.py) and are not obsolete; keep them in sync with the code that loads them. Related policy logic also exists in src/confcom/azext_confcom/lib/policy.py.

Copilot uses AI. Check for mistakes.
Comment thread src/confcom/HISTORY.rst
===============

2.0.0b1
+++++
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

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

The reStructuredText section underline length doesn’t match the header length (2.0.0b1 has 7 characters but the underline is only 5 +). This will produce docutils/Sphinx formatting warnings; adjust the underline to match the version string length (consistent with other entries like 1.8.0).

Suggested change
+++++
+++++++

Copilot uses AI. Check for mistakes.
@necusjz necusjz added skip-cal-version and removed release-version-block Updates do not qualify release version rules. NOTE: please do not edit it manually. labels Apr 14, 2026
@necusjz
Copy link
Copy Markdown
Member

necusjz commented Apr 14, 2026

/azp run

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines successfully started running 2 pipeline(s).

@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines:
2 pipeline(s) require an authorized user to comment /azp run to run.

This is not, in fact, where parameters and variables are populated. That happens
in the constructor for AciPolicy.
@azure-pipelines
Copy link
Copy Markdown

Azure Pipelines:
2 pipeline(s) require an authorized user to comment /azp run to run.

@micromaomao
Copy link
Copy Markdown
Member Author

/azp run

@azure-pipelines
Copy link
Copy Markdown

Commenter does not have sufficient privileges for PR 9776 in repo Azure/azure-cli-extensions

@micromaomao
Copy link
Copy Markdown
Member Author

Closing this as @MahatiC will create a new one

need to fix up:

  • Take command line option for platform
  • container.platform is not a valid field in ARM (doc) - remove it from load_policy_from_arm_template_str
  • Check that osType in ARM template matches with this command line

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants