Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package azure-cli-core for openSUSE:Factory checked in at 2025-03-13 15:07:44 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/azure-cli-core (Old) and /work/SRC/openSUSE:Factory/.azure-cli-core.new.19136 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "azure-cli-core" Thu Mar 13 15:07:44 2025 rev:78 rq:1252717 version:2.70.0 Changes: -------- --- /work/SRC/openSUSE:Factory/azure-cli-core/azure-cli-core.changes 2025-02-14 19:21:12.451465493 +0100 +++ /work/SRC/openSUSE:Factory/.azure-cli-core.new.19136/azure-cli-core.changes 2025-03-13 15:08:32.936117957 +0100 @@ -1,0 +2,9 @@ +Wed Mar 12 13:16:29 UTC 2025 - John Paul Adrian Glaubitz <adrian.glaub...@suse.com> + +- New upstream release + + Version 2.70.0 + + For detailed information about changes see the + HISTORY.rst file provided with this package +- Update Requires from setup.py + +------------------------------------------------------------------- Old: ---- azure_cli_core-2.69.0.tar.gz New: ---- azure_cli_core-2.70.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ azure-cli-core.spec ++++++ --- /var/tmp/diff_new_pack.1tbLfe/_old 2025-03-13 15:08:33.400137420 +0100 +++ /var/tmp/diff_new_pack.1tbLfe/_new 2025-03-13 15:08:33.404137588 +0100 @@ -24,7 +24,7 @@ %global _sitelibdir %{%{pythons}_sitelib} Name: azure-cli-core -Version: 2.69.0 +Version: 2.70.0 Release: 0 Summary: Microsoft Azure CLI Core Module License: MIT @@ -61,6 +61,7 @@ Requires: %{pythons}-pip Requires: %{pythons}-pkginfo >= 1.5.0.1 Requires: %{pythons}-psutil >= 5.9 +Requires: %{pythons}-py-deviceid Requires: %{pythons}-pyOpenSSL >= 17.1.0 Requires: %{pythons}-requests < 3.0.0 Requires: %{pythons}-requests >= 2.25.1 ++++++ azure_cli_core-2.69.0.tar.gz -> azure_cli_core-2.70.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/HISTORY.rst new/azure_cli_core-2.70.0/HISTORY.rst --- old/azure_cli_core-2.69.0/HISTORY.rst 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/HISTORY.rst 2025-02-26 07:24:09.000000000 +0100 @@ -3,6 +3,13 @@ Release History =============== +2.70.0 +++++++ +* Resolve CVE-2024-12797 (#30816) +* Drop Track 1 SDK authentication (#29631) +* `aaz`: Add cross tenants control for `AAZResourceIdArgFormat` (#30817) +* `aaz`: Support `Any` type with full value shorthand syntax allowed (#30868) + 2.69.0 ++++++ * `aaz`: Support simple type parsed from string value (#30623) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/PKG-INFO new/azure_cli_core-2.70.0/PKG-INFO --- old/azure_cli_core-2.69.0/PKG-INFO 2025-02-05 07:39:53.460627000 +0100 +++ new/azure_cli_core-2.70.0/PKG-INFO 2025-02-26 07:24:39.789584600 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.2 Name: azure-cli-core -Version: 2.69.0 +Version: 2.70.0 Summary: Microsoft Azure Command-Line Tools Core Module Home-page: https://github.com/Azure/azure-cli Author: Microsoft Corporation @@ -26,6 +26,7 @@ Requires-Dist: humanfriendly~=10.0 Requires-Dist: jmespath Requires-Dist: knack~=0.11.0 +Requires-Dist: microsoft-security-utilities-secret-masker~=1.0.0b2 Requires-Dist: msal-extensions==1.2.0 Requires-Dist: msal[broker]==1.31.2b1 Requires-Dist: msrestazure~=0.6.4 @@ -34,8 +35,8 @@ Requires-Dist: psutil>=5.9; sys_platform != "cygwin" Requires-Dist: PyJWT>=2.1.0 Requires-Dist: pyopenssl>=17.1.0 +Requires-Dist: py-deviceid Requires-Dist: requests[socks] -Requires-Dist: microsoft-security-utilities-secret-masker~=1.0.0b2 Dynamic: author Dynamic: author-email Dynamic: classifier diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/__init__.py new/azure_cli_core-2.70.0/azure/cli/core/__init__.py --- old/azure_cli_core-2.69.0/azure/cli/core/__init__.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/__init__.py 2025-02-26 07:24:09.000000000 +0100 @@ -4,7 +4,7 @@ # -------------------------------------------------------------------------------------------- # pylint: disable=line-too-long -__version__ = "2.69.0" +__version__ = "2.70.0" import os import sys diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/_profile.py new/azure_cli_core-2.70.0/azure/cli/core/_profile.py --- old/azure_cli_core-2.69.0/azure/cli/core/_profile.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/_profile.py 2025-02-26 07:24:09.000000000 +0100 @@ -385,16 +385,8 @@ identity.logout_all_users() identity.logout_all_service_principal() - def get_login_credentials(self, resource=None, subscription_id=None, aux_subscriptions=None, aux_tenants=None): - """Get a CredentialAdaptor instance to be used with both Track 1 and Track 2 SDKs. - - :param resource: The resource ID to acquire an access token. Only provide it for Track 1 SDKs. - :param subscription_id: - :param aux_subscriptions: - :param aux_tenants: - """ - resource = resource or self.cli_ctx.cloud.endpoints.active_directory_resource_id - + def get_login_credentials(self, subscription_id=None, aux_subscriptions=None, aux_tenants=None): + """Get a credential compatible with Track 2 SDK.""" if aux_tenants and aux_subscriptions: raise CLIError("Please specify only one of aux_subscriptions and aux_tenants, not both") @@ -407,7 +399,7 @@ from .auth.msal_credentials import CloudShellCredential from azure.cli.core.auth.credential_adaptor import CredentialAdaptor # The credential must be wrapped by CredentialAdaptor so that it can work with Track 1 SDKs. - cred = CredentialAdaptor(CloudShellCredential(), resource=resource) + cred = CredentialAdaptor(CloudShellCredential()) elif managed_identity_type: # managed identity @@ -415,9 +407,13 @@ from .auth.msal_credentials import ManagedIdentityCredential from azure.cli.core.auth.credential_adaptor import CredentialAdaptor # The credential must be wrapped by CredentialAdaptor so that it can work with Track 1 SDKs. - cred = CredentialAdaptor(ManagedIdentityCredential(), resource=resource) + cred = CredentialAdaptor(ManagedIdentityCredential()) else: - cred = MsiAccountTypes.msi_auth_factory(managed_identity_type, managed_identity_id, resource) + # The resource is merely used by msrestazure to get the first access token. + # It is not actually used in an API invocation. + cred = MsiAccountTypes.msi_auth_factory( + managed_identity_type, managed_identity_id, + self.cli_ctx.cloud.endpoints.active_directory_resource_id) else: # user and service principal @@ -436,9 +432,7 @@ for external_tenant in external_tenants: external_credentials.append(self._create_credential(account, tenant_id=external_tenant)) from azure.cli.core.auth.credential_adaptor import CredentialAdaptor - cred = CredentialAdaptor(credential, - auxiliary_credentials=external_credentials, - resource=resource) + cred = CredentialAdaptor(credential, auxiliary_credentials=external_credentials) return (cred, str(account[_SUBSCRIPTION_ID]), diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/__init__.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/__init__.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/__init__.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/__init__.py 2025-02-26 07:24:09.000000000 +0100 @@ -12,7 +12,8 @@ from ._arg import AAZArgumentsSchema, AAZArgEnum, AAZStrArg, AAZIntArg, AAZObjectArg, AAZDictArg, \ AAZFreeFormDictArg, AAZFloatArg, AAZBaseArg, AAZBoolArg, AAZListArg, AAZResourceGroupNameArg, \ AAZResourceLocationArg, AAZResourceIdArg, AAZSubscriptionIdArg, AAZUuidArg, AAZDateArg, AAZTimeArg, \ - AAZDateTimeArg, AAZDurationArg, AAZFileArg, AAZPasswordArg, AAZPaginationTokenArg, AAZPaginationLimitArg + AAZDateTimeArg, AAZDurationArg, AAZFileArg, AAZPasswordArg, AAZPaginationTokenArg, AAZPaginationLimitArg, \ + AAZAnyTypeArg from ._arg_fmt import AAZStrArgFormat, AAZIntArgFormat, AAZFloatArgFormat, AAZBoolArgFormat, AAZObjectArgFormat, \ AAZDictArgFormat, AAZFreeFormDictArgFormat, AAZListArgFormat, AAZResourceLocationArgFormat, \ AAZResourceIdArgFormat, AAZSubscriptionIdArgFormat, AAZUuidFormat, AAZDateFormat, AAZTimeFormat, \ @@ -22,7 +23,7 @@ from ._command import AAZCommand, AAZWaitCommand, AAZCommandGroup, \ register_callback, register_command, register_command_group, load_aaz_command_table, link_helper from ._field_type import AAZIntType, AAZFloatType, AAZStrType, AAZBoolType, AAZDictType, AAZFreeFormDictType, \ - AAZListType, AAZObjectType, AAZIdentityObjectType + AAZListType, AAZObjectType, AAZIdentityObjectType, AAZAnyType from ._operation import AAZHttpOperation, AAZJsonInstanceUpdateOperation, AAZGenericInstanceUpdateOperation, \ AAZJsonInstanceDeleteOperation, AAZJsonInstanceCreateOperation from ._prompt import AAZPromptInput, AAZPromptPasswordInput diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_arg.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_arg.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_arg.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_arg.py 2025-02-26 07:24:09.000000000 +0100 @@ -13,11 +13,11 @@ from knack.util import status_tag_messages from knack.log import get_logger -from ._arg_action import AAZSimpleTypeArgAction, AAZObjectArgAction, AAZDictArgAction, AAZFreeFormDictArgAction, \ - AAZListArgAction, AAZGenericUpdateAction, AAZGenericUpdateForceStringAction +from ._arg_action import AAZSimpleTypeArgAction, AAZObjectArgAction, AAZDictArgAction, \ + AAZListArgAction, AAZGenericUpdateAction, AAZGenericUpdateForceStringAction, AAZAnyTypeArgAction from ._base import AAZBaseType, AAZUndefined from ._field_type import AAZObjectType, AAZStrType, AAZIntType, AAZBoolType, AAZFloatType, AAZListType, AAZDictType, \ - AAZSimpleType, AAZFreeFormDictType + AAZSimpleType, AAZFreeFormDictType, AAZAnyType from ._field_value import AAZObject from ._arg_fmt import AAZObjectArgFormat, AAZListArgFormat, AAZDictArgFormat, AAZFreeFormDictArgFormat, \ AAZSubscriptionIdArgFormat, AAZResourceLocationArgFormat, AAZResourceIdArgFormat, AAZUuidFormat, AAZDateFormat, \ @@ -356,6 +356,28 @@ return "Float" +class AAZAnyTypeArg(AAZBaseArg, AAZAnyType): + + def _build_cmd_action(self): + class Action(AAZAnyTypeArgAction): + _schema = self # bind action class with current schema + return Action + + def to_cmd_arg(self, name, **kwargs): + from ._help import shorthand_help_messages + arg = super().to_cmd_arg(name, **kwargs) + short_summary = arg.type.settings.get('help', None) or '' + if short_summary: + short_summary += ' ' + short_summary += shorthand_help_messages['short-summary-anytype'] + arg.help = short_summary + return arg + + @property + def _type_in_help(self): + return "Any" + + class AAZCompoundTypeArg(AAZBaseArg): @abc.abstractmethod @@ -427,30 +449,15 @@ return f"Dict<String,{self.Element._type_in_help}>" -class AAZFreeFormDictArg(AAZBaseArg, AAZFreeFormDictType): +# Warning: This type should not be used any more, the new aaz-dev-tools only use AAZDictType with AAZAnyType +class AAZFreeFormDictArg(AAZDictArg, AAZFreeFormDictType): def __init__(self, fmt=None, **kwargs): fmt = fmt or AAZFreeFormDictArgFormat() super().__init__(fmt=fmt, **kwargs) - - def to_cmd_arg(self, name, **kwargs): - arg = super().to_cmd_arg(name, **kwargs) - short_summary = arg.type.settings.get('help', None) or '' - if short_summary: - short_summary += ' ' - short_summary += "Support json-file and yaml-file." - arg.help = short_summary - return arg - - def _build_cmd_action(self): - class Action(AAZFreeFormDictArgAction): - _schema = self # bind action class with current schema - - return Action - - @property - def _type_in_help(self): - return "Dict<String, Any>" + # for backward compatible, support nullable value here for AAZFreeFormDictArg, + # from the new code gen tools, it will avoid using AAZFreeFormDictArg + self._element = AAZAnyTypeArg(nullable=True) class AAZListArg(AAZCompoundTypeArg, AAZListType): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_arg_action.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_arg_action.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_arg_action.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_arg_action.py 2025-02-26 07:24:09.000000000 +0100 @@ -150,6 +150,14 @@ return AAZPromptInputOperation(prompt=cls._schema._blank, action_cls=cls) data = copy.deepcopy(cls._schema._blank) + if data is None: + if cls._schema._nullable: + return data + raise AAZInvalidValueError("field is not nullable") + + if cls._schema.DataType == str and isinstance(data, (int, bool, float)): + data = str(data).lower() # convert to json raw values + if isinstance(data, str): # transfer string into correct data if cls._schema.enum: @@ -159,12 +167,86 @@ if isinstance(data, cls._schema.DataType): return data + if isinstance(data, int) and cls._schema.DataType == float: + return data + + raise AAZInvalidValueError(f"{cls._schema.DataType} type value expected, got '{data}'({type(data)})") + + +class AAZAnyTypeArgAction(AAZArgAction): + + @classmethod + def setup_operations(cls, dest_ops, values, prefix_keys=None): + if prefix_keys is None: + prefix_keys = [] + if values is None: + data = AAZBlankArgValue # use blank data when values string is None + else: + if isinstance(values, list): + assert prefix_keys # the values will be input as an list when parse singular option of a list argument + if len(values) != 1: + raise AAZInvalidValueError(f"only support 1 value, got {len(values)}: {values}") + values = values[0] + + if isinstance(values, str) and len(values) > 0: + try: + data = cls.decode_str(values) + except AAZShowHelp as aaz_help: + aaz_help.schema = cls._schema + raise aaz_help + else: + data = values + data = cls.format_data(data) + dest_ops.add(data, *prefix_keys) + + @classmethod + def decode_str(cls, value): + from azure.cli.core.util import get_file_json, shell_safe_json_parse, get_file_yaml + + # check if the value is a partial value + key, _, v = cls._str_parser.split_partial_value(value) + if key is not None: + raise AAZInvalidValueError( + "AnyType args only support full value shorthand syntax, " + "please don't use partial value shorthand syntax. " + "If it's a simple string, please wrap it with single quotes.") + + # read from file + path = os.path.expanduser(value) + if os.path.exists(path): + if path.endswith('.yml') or path.endswith('.yaml'): + # read from yaml file + v = get_file_yaml(path) + else: + # read from json file + v = get_file_json(path, preserve_order=True) + else: + try: + v = cls._str_parser(value) + except AAZInvalidShorthandSyntaxError as shorthand_ex: + try: + v = shell_safe_json_parse(value, True) + except Exception as ex: + logger.debug(ex) # log parse json failed expression + raise shorthand_ex # raise shorthand syntax exception + return v + + @classmethod + def format_data(cls, data): + if data == AAZBlankArgValue: + if cls._schema._blank == AAZUndefined: + raise AAZInvalidValueError("argument value cannot be blank") + if isinstance(cls._schema._blank, AAZPromptInput): + # Postpone the prompt input when apply the operation. + # In order not to break the logic of displaying help or validating other parameters. + return AAZPromptInputOperation(prompt=cls._schema._blank, action_cls=cls) + data = copy.deepcopy(cls._schema._blank) + if data is None: if cls._schema._nullable: return data raise AAZInvalidValueError("field is not nullable") - - raise AAZInvalidValueError(f"{cls._schema.DataType} type value expected, got '{data}'({type(data)})") + return data class AAZCompoundTypeArgAction(AAZArgAction): # pylint: disable=abstract-method @@ -245,7 +327,7 @@ # simple type v = cls._str_parser(value, is_simple=True) else: - # compound type + # compound type or any type # read from file path = os.path.expanduser(value) if os.path.exists(path): @@ -264,7 +346,6 @@ except Exception as ex: logger.debug(ex) # log parse json failed expression raise shorthand_ex # raise shorthand syntax exception - return v @@ -323,52 +404,6 @@ raise AAZInvalidValueError(f"dict type value expected, got '{data}'({type(data)})") - -class AAZFreeFormDictArgAction(AAZSimpleTypeArgAction): - - @classmethod - def decode_str(cls, value): - from azure.cli.core.util import get_file_json, shell_safe_json_parse, get_file_yaml - - if len(value) == 0: - # the express "a=" will return the blank value of schema 'a' - return AAZBlankArgValue - - path = os.path.expanduser(value) - if os.path.exists(path): - if path.endswith('.yml') or path.endswith('.yaml'): - # read from yaml file - v = get_file_yaml(path) - else: - # read from json file - v = get_file_json(path, preserve_order=True) - else: - try: - v = shell_safe_json_parse(value, True) - except Exception as ex: - logger.debug(ex) # log parse json failed expression - raise - return v - - @classmethod - def format_data(cls, data): - if data == AAZBlankArgValue: - if cls._schema._blank == AAZUndefined: - raise AAZInvalidValueError("argument value cannot be blank") - assert not isinstance(cls._schema._blank, AAZPromptInput), "Prompt input is not supported in " \ - "FreeFormDict args." - data = copy.deepcopy(cls._schema._blank) - - if isinstance(data, dict): - return data - - if data is None: - if cls._schema._nullable: - return data - raise AAZInvalidValueError("field is not nullable") - - raise AAZInvalidValueError(f"dict type value expected, got '{data}'({type(data)})") - class AAZListArgAction(AAZCompoundTypeArgAction): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_arg_browser.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_arg_browser.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_arg_browser.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_arg_browser.py 2025-02-26 07:24:09.000000000 +0100 @@ -62,23 +62,10 @@ else: raise NotImplementedError() + # Warning: This method is not used by the new aaz-dev-tools, it should be kept for backward compatibility def get_anytype_elements(self): """Iter over sub elements of list or dict.""" - if self._arg_data is None: - # stop iteration - return - - if isinstance(self._arg_data, dict): - for k, d in self._arg_data.items(): - v = self._arg_value[k] - if isinstance(v, AAZBaseValue): - # ignore fixed type element - continue - # build AAZBaseValue from data without schema - v = AAZBaseValue(None, d) - yield k, AAZArgBrowser(v, d, parent=None) - else: - raise NotImplementedError() + return self.get_elements() @property def data(self): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_arg_fmt.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_arg_fmt.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_arg_fmt.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_arg_fmt.py 2025-02-26 07:24:09.000000000 +0100 @@ -15,7 +15,7 @@ from ._command_ctx import AAZCommandCtx from ._field_type import AAZSimpleType -from ._field_value import AAZUndefined, AAZSimpleValue, AAZDict, AAZFreeFormDict, AAZList, AAZObject +from ._field_value import AAZUndefined, AAZSimpleValue, AAZDict, AAZList, AAZObject from .exceptions import AAZInvalidArgValueError logger = get_logger(__name__) @@ -466,32 +466,9 @@ return value -class AAZFreeFormDictArgFormat(AAZBaseArgFormat): - - def __init__(self, max_properties=None, min_properties=None): - self._max_properties = max_properties - self._min_properties = min_properties - - def __call__(self, ctx, value): - assert isinstance(value, AAZFreeFormDict) - data = value._data - if data == AAZUndefined or data is None: - return value - - assert isinstance(data, dict) - - if value._is_patch: - return value - - if self._min_properties and len(value) < self._min_properties: - raise AAZInvalidArgValueError( - f"Invalid format: dict length is less than {self._min_properties}") - - if self._max_properties and len(value) > self._max_properties: - raise AAZInvalidArgValueError( - f"Invalid format: dict length is greater than {self._max_properties}") - - return value +# Warning: This type should not be used any more, the new aaz-dev-tools only use AAZDictArgFormat +class AAZFreeFormDictArgFormat(AAZDictArgFormat): + pass class AAZListArgFormat(AAZBaseArgFormat): @@ -659,14 +636,16 @@ return data - def __init__(self, template=None): + def __init__(self, template=None, cross_tenants=True): """ :param template: template property is used to verify a resource Id or construct resource Id. + :param cross_tenants: if cross_tenants is True, the resource id will apply to cross-tenants scenarios. """ self._template = None if template: self._template = self._Template(template) + self._cross_tenants = cross_tenants def __call__(self, ctx, value): from azure.mgmt.core.tools import parse_resource_id @@ -682,7 +661,7 @@ parsed_id = parse_resource_id(data) subscription_id = parsed_id.get('subscription', None) - if subscription_id: + if subscription_id and self._cross_tenants: # update subscription_id to support cross tenants ctx.update_aux_subscriptions(subscription_id) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_content_builder.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_content_builder.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_content_builder.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_content_builder.py 2025-02-26 07:24:09.000000000 +0100 @@ -4,8 +4,8 @@ # -------------------------------------------------------------------------------------------- from ._base import AAZBaseValue, AAZUndefined -from ._field_value import AAZSimpleValue, AAZBaseDictValue, AAZDict, AAZFreeFormDict, AAZList, AAZObject -from ._field_type import AAZObjectType +from ._field_value import AAZSimpleValue, AAZBaseDictValue, AAZDict, AAZList, AAZObject +from ._field_type import AAZObjectType, AAZAnyType from ._arg_browser import AAZArgBrowser # pylint: disable=protected-access, too-many-nested-blocks, too-many-return-statements @@ -131,19 +131,10 @@ return None + # Warning: This method is not used by the new aaz-dev-tools, it should be kept for backward compatibility def set_anytype_elements(self, arg_key=None): """Set any type elements of free from dictionary""" - for value, arg in zip(self._values, self._args): - if not isinstance(value, AAZFreeFormDict): - raise NotImplementedError() - - for key, sub_arg in arg.get_anytype_elements(): - if sub_arg is not None and sub_arg.data != AAZUndefined: - sub_arg = sub_arg.get_prop(arg_key) - - if sub_arg is not None and sub_arg.data != AAZUndefined: - if not sub_arg.is_patch and arg_key: - value[key] = sub_arg.data + self.set_elements(AAZAnyType, arg_key=arg_key) def discriminate_by(self, prop_name, prop_value): """discriminate object by a specify property""" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_field_type.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_field_type.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_field_type.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_field_type.py 2025-02-26 07:24:09.000000000 +0100 @@ -9,7 +9,7 @@ from azure.cli.core.util import shell_safe_json_parse from ._base import AAZBaseType, AAZValuePatch, AAZUndefined from ._field_value import AAZObject, AAZDict, AAZFreeFormDict, AAZList, AAZSimpleValue, \ - AAZIdentityObject + AAZIdentityObject, AAZAnyValue from ._utils import to_snack_case from .exceptions import AAZUnknownFieldError, AAZConflictFieldDefinitionError, AAZValuePrecisionLossError, \ AAZInvalidFieldError, AAZInvalidValueError @@ -111,6 +111,41 @@ return data +class AAZAnyType(AAZSimpleType): + """Any type""" + + _ValueCls = AAZAnyValue + + def process_data(self, data, **kwargs): + if isinstance(data, (AAZObject, AAZDict, AAZList)): + # convert them to simple dict, list, None or AAZUndefined values + value = data.to_serialized_data() + # TODO: may need to add warnings or raise error when treat the patch assign into the full assign. + # for the code gen commands it will not happen as the any type args only support full assign. + # but for the customization code, this will happen when convert AAZCompoundTypeArg to AAZAnyTypeArg + # if data._is_patch and isinstance(value, (dict, list)) and len(value): + # pass + data = value + + if data == None: # noqa: E711, pylint: disable=singleton-comparison + # data can be None or AAZSimpleValue == None + if self._nullable: + return None + return AAZValuePatch.build(self) + + if data == AAZUndefined: + return AAZValuePatch.build(self) + + if isinstance(data, AAZSimpleValue): + if data._is_patch: + # return value patch + return AAZValuePatch.build(self) + + return data._data + + return data + + # compound types class AAZObjectType(AAZBaseType): """Object value type""" @@ -356,13 +391,17 @@ return self.Element -class AAZFreeFormDictType(AAZBaseDictType): +# Warning: This type should not be used any more, the new aaz-dev-tools only use AAZDictType with AAZAnyType +class AAZFreeFormDictType(AAZDictType): """Free form dict value type""" _ValueCls = AAZFreeFormDict - def __getitem__(self, key): - return None + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + # for backward compatible, so support nullable for any type. + # from the new code gen tools, it will avoid using AAZFreeFormDictType + self._element = AAZAnyType(nullable=True) class AAZListType(AAZBaseType): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_field_value.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_field_value.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_field_value.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_field_value.py 2025-02-26 07:24:09.000000000 +0100 @@ -3,10 +3,7 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- # pylint: disable=protected-access -import copy - from ._base import AAZBaseValue, AAZValuePatch, AAZUndefined -from .exceptions import AAZInvalidValueError import abc @@ -57,6 +54,11 @@ return result +class AAZAnyValue(AAZSimpleValue): # pylint: disable=too-few-public-methods + # TODO: may need to override the __getitem__, __setitem__, __delitem__, __getattr__, __setattr__, __delattr__, + pass + + class AAZObject(AAZBaseValue): def __init__(self, schema, data): @@ -261,60 +263,13 @@ return result -class AAZFreeFormDict(AAZBaseDictValue): +class AAZFreeFormDict(AAZDict): def __init__(self, schema, data): from ._field_type import AAZFreeFormDictType assert isinstance(schema, AAZFreeFormDictType) super().__init__(schema, data) - def __getitem__(self, key) -> AAZBaseValue: - item_schema = self._schema[key] - if item_schema is None: - # free form - return self._data[key] - if key not in self._data: - self._data[key] = AAZValuePatch.build(item_schema) - return item_schema._ValueCls(item_schema, self._data[key]) # return as AAZValue - - def __setitem__(self, key, data): - item_schema = self._schema[key] - if item_schema is None: - # free form - if isinstance(data, AAZValuePatch): - raise AAZInvalidValueError("Not support value patch for Free-Form dict key") - if isinstance(data, AAZBaseValue): - if data._is_patch: - raise AAZInvalidValueError("Not support value patch for Free-Form dict key") - data = data._data - assert not isinstance(data, AAZBaseValue) - self._data[key] = copy.deepcopy(data) - return - - # For fixed key properties usage - self._data[key] = item_schema.process_data(data, key=key) - - def to_serialized_data(self, processor=None, **kwargs): - if self._data == AAZUndefined: - result = AAZUndefined - elif self._data is None: - result = None - else: - result = {} - for key, v in self.items(): - if isinstance(v, AAZBaseValue): - v = v.to_serialized_data(processor=processor, **kwargs) - if v == AAZUndefined: - continue - result[key] = v - - if not result and self._is_patch: - result = AAZUndefined - - if processor: - result = processor(self._schema, result) - return result - class AAZList(AAZBaseValue): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_help.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_help.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_help.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_help.py 2025-02-26 07:24:09.000000000 +0100 @@ -22,6 +22,7 @@ shorthand_help_messages = { "show-help": 'Try "??" to show more.', "short-summary": 'Support shorthand-syntax, json-file and yaml-file.', + "short-summary-anytype": 'Support shorthand-syntax(full value only), json-file and yaml-file.', "long-summary": 'See https://aka.ms/cli-shorthand for more about shorthand syntax.' } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/aaz/_utils.py new/azure_cli_core-2.70.0/azure/cli/core/aaz/_utils.py --- old/azure_cli_core-2.69.0/azure/cli/core/aaz/_utils.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/aaz/_utils.py 2025-02-26 07:24:09.000000000 +0100 @@ -4,7 +4,7 @@ # -------------------------------------------------------------------------------------------- import re from collections import OrderedDict - +import json from azure.cli.core.aaz.exceptions import AAZInvalidShorthandSyntaxError from ._help import AAZShowHelp from ._base import AAZBlankArgValue @@ -57,7 +57,7 @@ if remain.startswith('['): return self.parse_list(remain) - return self.parse_string(remain) + return self.parse_string(remain, convert_simple_type=True) def parse_dict(self, remain): # pylint: disable=too-many-statements result = OrderedDict() @@ -165,7 +165,7 @@ raise AAZInvalidShorthandSyntaxError(remain, idx, 1, "Expect character ']'") return result, idx - def parse_string(self, remain): + def parse_string(self, remain, convert_simple_type=False): idx = 0 if len(remain) and remain[0] == "'": return self.parse_single_quotes_string(remain) @@ -191,6 +191,14 @@ if remain[:idx] in self.HELP_EXPRESSIONS: raise AAZShowHelp() + if convert_simple_type: + try: + converted = json.loads(remain[:idx]) + if isinstance(converted, (str, int, float, bool)): + return converted, idx + except ValueError: + pass + return remain[:idx], idx @staticmethod diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/auth/credential_adaptor.py new/azure_cli_core-2.70.0/azure/cli/core/auth/credential_adaptor.py --- old/azure_cli_core-2.69.0/azure/cli/core/auth/credential_adaptor.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/auth/credential_adaptor.py 2025-02-26 07:24:09.000000000 +0100 @@ -3,24 +3,18 @@ # Licensed under the MIT License. See License.txt in the project root for license information. # -------------------------------------------------------------------------------------------- -import requests from knack.log import get_logger -from knack.util import CLIError - -from .util import resource_to_scopes logger = get_logger(__name__) class CredentialAdaptor: - def __init__(self, credential, resource=None, auxiliary_credentials=None): - """ - Adaptor to both - - Track 1: msrest.authentication.Authentication, which exposes signed_session - - Track 2: azure.core.credentials.TokenCredential, which exposes get_token + def __init__(self, credential, auxiliary_credentials=None): + """Cross-tenant credential adaptor. It takes a main credential and auxiliary credentials. + + It implements Track 2 SDK's azure.core.credentials.TokenCredential by exposing get_token. :param credential: Main credential from .msal_authentication - :param resource: AAD resource for Track 1 only :param auxiliary_credentials: Credentials from .msal_authentication for cross tenant authentication. Details about cross tenant authentication: https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/authenticate-multi-tenant @@ -28,33 +22,9 @@ self._credential = credential self._auxiliary_credentials = auxiliary_credentials - self._resource = resource - - def _get_token(self, scopes=None, **kwargs): - external_tenant_tokens = [] - # If scopes is not provided, use CLI-managed resource - scopes = scopes or resource_to_scopes(self._resource) - try: - token = self._credential.get_token(*scopes, **kwargs) - if self._auxiliary_credentials: - external_tenant_tokens = [cred.get_token(*scopes) for cred in self._auxiliary_credentials] - return token, external_tenant_tokens - except requests.exceptions.SSLError as err: - from azure.cli.core.util import SSLERROR_TEMPLATE - raise CLIError(SSLERROR_TEMPLATE.format(str(err))) - - def signed_session(self, session=None): - logger.debug("CredentialAdaptor.signed_session") - session = session or requests.Session() - token, external_tenant_tokens = self._get_token() - header = "{} {}".format('Bearer', token.token) - session.headers['Authorization'] = header - if external_tenant_tokens: - aux_tokens = ';'.join(['{} {}'.format('Bearer', tokens2.token) for tokens2 in external_tenant_tokens]) - session.headers['x-ms-authorization-auxiliary'] = aux_tokens - return session def get_token(self, *scopes, **kwargs): + """Get an access token from the main credential.""" logger.debug("CredentialAdaptor.get_token: scopes=%r, kwargs=%r", scopes, kwargs) # Discard unsupported kwargs: tenant_id, enable_cae @@ -62,10 +32,10 @@ if 'data' in kwargs: filtered_kwargs['data'] = kwargs['data'] - token, _ = self._get_token(scopes, **filtered_kwargs) - return token + return self._credential.get_token(*scopes, **filtered_kwargs) def get_auxiliary_tokens(self, *scopes, **kwargs): + """Get access tokens from auxiliary credentials.""" # To test cross-tenant authentication, see https://github.com/Azure/azure-cli/issues/16691 if self._auxiliary_credentials: return [cred.get_token(*scopes, **kwargs) for cred in self._auxiliary_credentials] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/commands/client_factory.py new/azure_cli_core-2.70.0/azure/cli/core/commands/client_factory.py --- old/azure_cli_core-2.69.0/azure/cli/core/commands/client_factory.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/commands/client_factory.py 2025-02-26 07:24:09.000000000 +0100 @@ -213,7 +213,6 @@ subscription_id=None, api_version=None, base_url_bound=True, - resource=None, sdk_profile=None, aux_subscriptions=None, aux_tenants=None, @@ -222,10 +221,6 @@ from azure.cli.core._profile import Profile logger.debug('Getting management service client client_type=%s', client_type.__name__) - # Track 1 SDK doesn't maintain the `resource`. The `resource` of the token is the one passed to - # get_login_credentials. - resource = resource or cli_ctx.cloud.endpoints.active_directory_resource_id - if credential: # Use a custom credential if not subscription_id: @@ -234,7 +229,7 @@ # Get a credential for the current `az login` context profile = Profile(cli_ctx=cli_ctx) credential, subscription_id, _ = profile.get_login_credentials( - subscription_id=subscription_id, resource=resource, + subscription_id=subscription_id, aux_subscriptions=aux_subscriptions, aux_tenants=aux_tenants) client_kwargs = {} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/profiles/_shared.py new/azure_cli_core-2.70.0/azure/cli/core/profiles/_shared.py --- old/azure_cli_core-2.69.0/azure/cli/core/profiles/_shared.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/profiles/_shared.py 2025-02-26 07:24:09.000000000 +0100 @@ -155,7 +155,7 @@ AZURE_API_PROFILES = { 'latest': { - ResourceType.MGMT_STORAGE: '2023-05-01', + ResourceType.MGMT_STORAGE: '2024-01-01', ResourceType.MGMT_NETWORK: '2022-01-01', ResourceType.MGMT_COMPUTE: SDKProfile('2024-07-01', { 'resource_skus': '2019-04-01', @@ -262,7 +262,7 @@ ResourceType.MGMT_ARO: '2023-11-22', ResourceType.MGMT_DATABOXEDGE: '2021-02-01-preview', ResourceType.MGMT_CUSTOMLOCATION: '2021-03-15-preview', - ResourceType.MGMT_CONTAINERSERVICE: SDKProfile('2024-09-01'), + ResourceType.MGMT_CONTAINERSERVICE: SDKProfile('2024-10-01'), ResourceType.MGMT_APPCONTAINERS: '2022-10-01', }, '2020-09-01-hybrid': { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure/cli/core/telemetry.py new/azure_cli_core-2.70.0/azure/cli/core/telemetry.py --- old/azure_cli_core-2.69.0/azure/cli/core/telemetry.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure/cli/core/telemetry.py 2025-02-26 07:24:09.000000000 +0100 @@ -158,6 +158,7 @@ 'Context.Default.VS.Core.Distro.Id': _get_distro_id(), # eg. 'centos' 'Context.Default.VS.Core.Distro.Version': _get_distro_version(), # eg. '8.4.2105' 'Context.Dafault.VS.Core.Istty': str(sys.stdin.isatty()), + 'Context.Default.VS.Core.DevDeviceId': _get_device_id(), 'Context.Default.VS.Core.User.Id': _get_installation_id(), 'Context.Default.VS.Core.User.IsMicrosoftInternal': 'False', 'Context.Default.VS.Core.User.IsOptedIn': 'True', @@ -572,6 +573,13 @@ @decorators.suppress_all_exceptions(fallback_return=None) +def _get_device_id(): + # This is a shared id with VS code telemetry + from deviceid import get_device_id + return get_device_id() + + +@decorators.suppress_all_exceptions(fallback_return=None) def _get_installation_id(): return _get_profile().get_installation_id() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure_cli_core.egg-info/PKG-INFO new/azure_cli_core-2.70.0/azure_cli_core.egg-info/PKG-INFO --- old/azure_cli_core-2.69.0/azure_cli_core.egg-info/PKG-INFO 2025-02-05 07:39:53.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure_cli_core.egg-info/PKG-INFO 2025-02-26 07:24:39.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.2 Name: azure-cli-core -Version: 2.69.0 +Version: 2.70.0 Summary: Microsoft Azure Command-Line Tools Core Module Home-page: https://github.com/Azure/azure-cli Author: Microsoft Corporation @@ -26,6 +26,7 @@ Requires-Dist: humanfriendly~=10.0 Requires-Dist: jmespath Requires-Dist: knack~=0.11.0 +Requires-Dist: microsoft-security-utilities-secret-masker~=1.0.0b2 Requires-Dist: msal-extensions==1.2.0 Requires-Dist: msal[broker]==1.31.2b1 Requires-Dist: msrestazure~=0.6.4 @@ -34,8 +35,8 @@ Requires-Dist: psutil>=5.9; sys_platform != "cygwin" Requires-Dist: PyJWT>=2.1.0 Requires-Dist: pyopenssl>=17.1.0 +Requires-Dist: py-deviceid Requires-Dist: requests[socks] -Requires-Dist: microsoft-security-utilities-secret-masker~=1.0.0b2 Dynamic: author Dynamic: author-email Dynamic: classifier diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/azure_cli_core.egg-info/requires.txt new/azure_cli_core-2.70.0/azure_cli_core.egg-info/requires.txt --- old/azure_cli_core-2.69.0/azure_cli_core.egg-info/requires.txt 2025-02-05 07:39:53.000000000 +0100 +++ new/azure_cli_core-2.70.0/azure_cli_core.egg-info/requires.txt 2025-02-26 07:24:39.000000000 +0100 @@ -5,6 +5,7 @@ humanfriendly~=10.0 jmespath knack~=0.11.0 +microsoft-security-utilities-secret-masker~=1.0.0b2 msal-extensions==1.2.0 msal[broker]==1.31.2b1 msrestazure~=0.6.4 @@ -12,8 +13,8 @@ pkginfo>=1.5.0.1 PyJWT>=2.1.0 pyopenssl>=17.1.0 +py-deviceid requests[socks] -microsoft-security-utilities-secret-masker~=1.0.0b2 [:sys_platform != "cygwin"] psutil>=5.9 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/azure_cli_core-2.69.0/setup.py new/azure_cli_core-2.70.0/setup.py --- old/azure_cli_core-2.69.0/setup.py 2025-02-05 07:39:11.000000000 +0100 +++ new/azure_cli_core-2.70.0/setup.py 2025-02-26 07:24:09.000000000 +0100 @@ -8,7 +8,7 @@ from codecs import open from setuptools import setup, find_packages -VERSION = "2.69.0" +VERSION = "2.70.0" # If we have source, validate that our version numbers match # This should prevent uploading releases with mismatched versions. @@ -52,6 +52,7 @@ 'humanfriendly~=10.0', 'jmespath', 'knack~=0.11.0', + 'microsoft-security-utilities-secret-masker~=1.0.0b2', 'msal-extensions==1.2.0', 'msal[broker]==1.31.2b1', 'msrestazure~=0.6.4', @@ -61,8 +62,8 @@ 'psutil>=5.9; sys_platform != "cygwin"', 'PyJWT>=2.1.0', 'pyopenssl>=17.1.0', # https://github.com/pyca/pyopenssl/pull/612 + 'py-deviceid', 'requests[socks]', - 'microsoft-security-utilities-secret-masker~=1.0.0b2', ] with open('README.rst', 'r', encoding='utf-8') as f: