Skip to content

[ACR] add breaking change message#9655

Closed
nguyenm2151 wants to merge 7 commits intoAzure:mainfrom
nguyenm2151:main
Closed

[ACR] add breaking change message#9655
nguyenm2151 wants to merge 7 commits intoAzure:mainfrom
nguyenm2151:main

Conversation

@nguyenm2151
Copy link


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.

Copilot AI review requested due to automatic review settings March 6, 2026 17:29
@azure-client-tools-bot-prd
Copy link

Validation for Breaking Change Starting...

Thanks for your contribution!

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

Hi @nguyenm2151,
Please write the description of changes which can be perceived by customers into HISTORY.rst.
If you want to release a new extension version, please update the version in setup.py as well.

@yonzhan
Copy link
Collaborator

yonzhan commented Mar 6, 2026

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

@nguyenm2151 nguyenm2151 closed this Mar 6, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

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>

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

This PR updates the acrtransfer Azure CLI extension to support new ACR import/export pipeline storage authentication modes by moving to a newer vendored Container Registry management SDK and surfacing validation, guidance, and scenario coverage for the new flags.

Changes:

  • Vendor and switch to Container Registry management SDK 2025-06-01-preview for pipeline operations.
  • Add --storage-access-mode validation (Entra managed identity vs SAS token) and update pipeline create logic accordingly.
  • Add scenario tests covering both auth modes and identity behaviors.

Reviewed changes

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

Show a summary per file
File Description
src/acrtransfer/azext_acrtransfer/vendored_sdks/containerregistry/v2025_06_01_preview/** Adds new vendored SDK version used by the extension for pipeline operations.
src/acrtransfer/azext_acrtransfer/commands.py Points command groups at the new SDK operation templates and min API.
src/acrtransfer/azext_acrtransfer/_params.py Introduces --storage-access-mode and updates help text/argument wiring.
src/acrtransfer/azext_acrtransfer/_validators.py Adds validation/translation rules for storage access mode vs secret URI.
src/acrtransfer/azext_acrtransfer/exportpipeline.py Updates export pipeline creation to set storage_access_mode and prints permission guidance.
src/acrtransfer/azext_acrtransfer/importpipeline.py Updates import pipeline creation to set storage_access_mode and prints permission guidance.
src/acrtransfer/azext_acrtransfer/pipelinerun.py Adds diagnostic logging about which storage auth method is being used.
src/acrtransfer/azext_acrtransfer/utility_functions.py Switches model imports to the new SDK version.
src/acrtransfer/azext_acrtransfer/tests/latest/test_acrtransfer_pipelines.py Adds scenario tests for import/export pipelines across auth/identity modes.

Comment on lines +15 to +40
def _extract_storage_account_resource_id(subscription_id, resource_group_name, container_uri):
"""Extract storage account resource ID from container URI.
Expected format: https://<storage-account-name>.blob.core.windows.net/<container-name>
"""
try:
# Parse the URI to get storage account name
from urllib.parse import urlparse
parsed = urlparse(container_uri)
storage_account_name = parsed.hostname.split('.')[0]
return f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.Storage/storageAccounts/{storage_account_name}"
except Exception:
return "<storage-account-resource-id>"


def _extract_keyvault_resource_id(subscription_id, resource_group_name, keyvault_secret_uri):
"""Extract key vault resource ID from secret URI.
Expected format: https://<keyvault-name>.vault.azure.net/secrets/<secret-name>
"""
try:
from urllib.parse import urlparse
parsed = urlparse(keyvault_secret_uri)
keyvault_name = parsed.hostname.split('.')[0]
return f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.KeyVault/vaults/{keyvault_name}"
except Exception:
return "<key-vault-resource-id>"

Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The new helper functions for extracting resource IDs and printing permission guidance are duplicated in both importpipeline.py and exportpipeline.py. To reduce drift and simplify future changes, consider moving these helpers into utility_functions.py (or a dedicated module) and reuse them from both pipeline implementations.

Copilot uses AI. Check for mistakes.
Comment on lines +62 to +63
logger.warning("Please run:")
logger.warning(" az role assignment create --assignee \"%s\" --role \"Key Vault Secrets User\" --scope \"%s\"", principal_id, keyvault_resource_id)
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The Key Vault guidance always suggests an RBAC role assignment (Key Vault Secrets User). If the vault is configured with access policies (RBAC disabled), this instruction won’t work and users will need a KV access policy instead. Please adjust the guidance (or detect/mention the KV authorization mode) so the instructions are actionable in both configurations.

Suggested change
logger.warning("Please run:")
logger.warning(" az role assignment create --assignee \"%s\" --role \"Key Vault Secrets User\" --scope \"%s\"", principal_id, keyvault_resource_id)
logger.warning("If your Key Vault uses Azure RBAC for access control, you can run:")
logger.warning(" az role assignment create --assignee \"%s\" --role \"Key Vault Secrets User\" --scope \"%s\"", principal_id, keyvault_resource_id)
logger.warning("If your Key Vault uses access policies (RBAC disabled), configure a Key Vault access policy granting this managed identity at least 'get' permission on secrets.")

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +41
def _extract_storage_account_resource_id(subscription_id, resource_group_name, container_uri):
"""Extract storage account resource ID from container URI.
Expected format: https://<storage-account-name>.blob.core.windows.net/<container-name>
"""
try:
# Parse the URI to get storage account name
from urllib.parse import urlparse
parsed = urlparse(container_uri)
storage_account_name = parsed.hostname.split('.')[0]
return f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.Storage/storageAccounts/{storage_account_name}"
except Exception:
return "<storage-account-resource-id>"


def _extract_keyvault_resource_id(subscription_id, resource_group_name, keyvault_secret_uri):
"""Extract key vault resource ID from secret URI.
Expected format: https://<keyvault-name>.vault.azure.net/secrets/<secret-name>
"""
try:
from urllib.parse import urlparse
parsed = urlparse(keyvault_secret_uri)
keyvault_name = parsed.hostname.split('.')[0]
return f"/subscriptions/{subscription_id}/resourceGroups/{resource_group_name}/providers/Microsoft.KeyVault/vaults/{keyvault_name}"
except Exception:
return "<key-vault-resource-id>"

Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The new helper functions for extracting resource IDs and printing permission guidance are duplicated in both exportpipeline.py and importpipeline.py. Consider consolidating them in a shared helper module to avoid divergent behavior and repeated maintenance.

Copilot uses AI. Check for mistakes.
Comment on lines +63 to +65
logger.warning("Please run:")
logger.warning(" az role assignment create --assignee \"%s\" --role \"Key Vault Secrets User\" --scope \"%s\"", principal_id, keyvault_resource_id)
logger.warning("Note: If the Key Vault is in a different resource group, update the --scope parameter accordingly.")
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The Key Vault permission guidance always recommends an RBAC role assignment. For vaults using access policies (RBAC disabled), the recommended command won’t grant secret access. Consider updating the guidance to mention/access-policy steps or to detect and tailor instructions to the vault’s authorization mode.

Suggested change
logger.warning("Please run:")
logger.warning(" az role assignment create --assignee \"%s\" --role \"Key Vault Secrets User\" --scope \"%s\"", principal_id, keyvault_resource_id)
logger.warning("Note: If the Key Vault is in a different resource group, update the --scope parameter accordingly.")
logger.warning("If your Key Vault is configured to use Azure role-based access control (RBAC), you can grant access by running:")
logger.warning(" az role assignment create --assignee \"%s\" --role \"Key Vault Secrets User\" --scope \"%s\"", principal_id, keyvault_resource_id)
logger.warning("Note: If the Key Vault is in a different resource group, update the --scope parameter accordingly.")
logger.warning("If your Key Vault is configured to use access policies (RBAC disabled), instead configure an access policy for this managed identity, for example:")
logger.warning(" az keyvault set-policy --name <key-vault-name> --object-id \"%s\" --secret-permissions get list", principal_id)
logger.warning("Ensure that you use the correct Key Vault name and any additional secret permissions required by your scenario.")

Copilot uses AI. Check for mistakes.
Comment on lines +100 to +102
logger.warning("Authenticating to Storage Account using Storage SAS Token.")
except Exception:
pass
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

get_pipelinerun swallows all exceptions when trying to resolve the pipeline and determine storage_access_mode. A bare except Exception: pass makes diagnosing real failures difficult and can hide regressions. Please catch the specific exceptions you expect (e.g., HttpResponseError/ResourceNotFoundError) and log at debug level when the lookup fails.

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +84
# Generate SAS token and store in Key Vault
from datetime import datetime, timedelta
expiry = (datetime.utcnow() + timedelta(days=30)).strftime('%Y-%m-%dT%H:%MZ')
sas_token = self.cmd('storage container generate-sas '
'--account-name {storage_account} '
'--name {container} '
'--permissions racwdl '
f'--expiry {expiry} '
'-o tsv').output.strip()
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The test generates a container SAS token before the blob container is created. az storage container generate-sas typically expects the container to exist (or will fail depending on auth mode). Create the storage container before generating/storing the SAS token (or generate an account SAS instead).

Copilot uses AI. Check for mistakes.
Comment on lines +218 to +227
# Generate SAS token and store in Key Vault
from datetime import datetime, timedelta
expiry = (datetime.utcnow() + timedelta(days=30)).strftime('%Y-%m-%dT%H:%MZ')
sas_token = self.cmd('storage container generate-sas '
'--account-name {storage_account} '
'--name {container} '
'--permissions racwdl '
f'--expiry {expiry} '
'-o tsv').output.strip()

Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

Same issue as the export SAS test: the SAS token is generated before the storage container is created. Move the container creation ahead of storage container generate-sas (or switch to an account SAS) to avoid intermittent failures.

Copilot uses AI. Check for mistakes.
Comment on lines 18 to +21
c.argument('storage_account_container_uri', options_list=['--storage-container-uri', '-c'], validator=validate_storage_account_container_uri, help='Storage account container URI of the source or target storage account container of the form https://$MyStorageAccount.blob.core.windows.net/$MyContainer. Note that the URI may be different outside of AzureCloud.')
c.argument('keyvault_secret_uri', options_list=['--secret-uri', '-s'], validator=validate_keyvault_secret_uri, help='Keyvault secret URI containing a valid SAS token to the associated storage account of the form https://$MyKeyvault.vault.azure.net/secrets/$MySecret. Note that the URI may be different outside of AzureCloud.')
c.argument('user_assigned_identity_resource_id', options_list=['--assign-identity', '-i'], validator=validate_user_assigned_identity_resource_id, help='User assigned identity resource ID of the form /subscriptions/$MySubID/resourceGroups/$MyRG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$MyIdentity.')
c.argument('storage_access_mode', options_list=['--storage-access-mode', '-m'], validator=validate_storage_access_mode_and_secret_uri, help='Storage account access mode. Allowed values: entra-mi-auth, storage-sas-token. When using entra-mi-auth, a managed identity is required (use --assign-identity).')
c.argument('keyvault_secret_uri', options_list=['--secret-uri', '-s'], validator=validate_keyvault_secret_uri, help='Keyvault secret URI containing a valid SAS token to the associated storage account of the form https://$MyKeyvault.vault.azure.net/secrets/$MySecret. Note that the URI may be different outside of AzureCloud. Required when --storage-access-mode is storage-sas-token.')
c.argument('user_assigned_identity_resource_id', options_list=['--assign-identity', '-i'], validator=validate_user_assigned_identity_resource_id, help='Managed identity for the pipeline. Provide a user-assigned identity resource ID of the form /subscriptions/$MySubID/resourceGroups/$MyRG/providers/Microsoft.ManagedIdentity/userAssignedIdentities/$MyIdentity, or use [system] to provision a system-assigned identity. When using --storage-access-mode entra-mi-auth, if not specified or if [system] is used, a system-assigned managed identity will be automatically provisioned.')
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

storage_access_mode is added under the generic argument_context('acr'), which makes --storage-access-mode appear on all az acr ... commands (including unrelated ones). Consider scoping this argument (and its validator) to only the acr import-pipeline create / acr export-pipeline create command contexts to avoid polluting the broader ACR command surface.

Copilot uses AI. Check for mistakes.
@github-actions
Copy link
Contributor

github-actions bot commented Mar 6, 2026

Hi @nguyenm2151

Release Suggestions

Module: acrtransfer

  • Please log updates into to src/acrtransfer/HISTORY.rst
  • Update VERSION to 1.1.1b1 in src/acrtransfer/setup.py

Notes

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.

3 participants