Skip to content

[Role] Feature: Add az role deny-assignment create/delete commands#33109

Open
jruttle wants to merge 13 commits into
Azure:devfrom
jruttle:jruttle/add-deny-assignment-commands
Open

[Role] Feature: Add az role deny-assignment create/delete commands#33109
jruttle wants to merge 13 commits into
Azure:devfrom
jruttle:jruttle/add-deny-assignment-commands

Conversation

@jruttle

@jruttle jruttle commented Mar 31, 2026

Copy link
Copy Markdown
Member

Description

Adds az role deny-assignment create and az role deny-assignment delete commands for managing user-assigned deny assignments, matching the existing az role assignment pattern.

This implements the PUT/DELETE operations added in the Microsoft.Authorization/denyAssignments API (2024-07-01-preview), as specified in TypeSpec PR #41617.

Two Assignment Modes

The create command supports two modes for targeting principals:

Everyone mode (default): Denies all principals at the scope. At least one excluded principal is required via --exclude-principal-ids:

az role deny-assignment create --name "DenyAll" --scope /subscriptions/{sub} \
    --actions "Microsoft.Compute/virtualMachines/delete" \
    --exclude-principal-ids {your-object-id}

Per-principal mode: Denies a specific User or ServicePrincipal via --principal-id and --principal-type:

az role deny-assignment create --name "DenyUser" --scope /subscriptions/{sub} \
    --actions "Microsoft.Compute/virtualMachines/delete" \
    --principal-id {user-object-id} --principal-type User

Service Constraints

User-assigned deny assignments have specific restrictions enforced by the service:

  • Group principals are not permitted — only User or ServicePrincipal
  • No DataActions — only Actions/NotActions are supported
  • No Read actions — actions like */read are not permitted
  • No DoNotApplyToChildScopes — this property is not supported
  • Single principal per UADA — one principal per deny assignment (enforced by backend)

Commands

  • az role deny-assignment list — List deny assignments (existing, enhanced)
  • az role deny-assignment show — Show a deny assignment (existing, enhanced)
  • az role deny-assignment create — Create a user-assigned deny assignment
  • az role deny-assignment delete — Delete a user-assigned deny assignment

Files Changed

  • commands.py — Command registration for role deny-assignment group
  • custom.py — Business logic with dual-mode principal handling and validation
  • _params.py — Parameter definitions including --principal-id and --principal-type
  • _help.py — Help text with examples for both Everyone and per-principal modes
  • linter_exclusions.yml — Exclusions for long parameter names
  • tests/latest/test_deny_assignment.py — Unit tests (list, show, CRUD, per-principal, Group rejection, param validation)

Dependency

Note: The create and delete operations depend on azure-mgmt-authorization 5.0.0b2 (released 7 May 2026 on PyPI), which includes the create_or_update and delete methods on DenyAssignmentsOperations.

Testing

Tests are included in test_deny_assignment.py. Full end-to-end testing requires:

  1. A subscription with the Microsoft.Authorization/SubscriptionAllowedToOperateUserAssignedDenyAssignment feature flag registered
  2. The updated Python SDK with create/delete support

Related

Copilot AI review requested due to automatic review settings March 31, 2026 13:10
@azure-client-tools-bot-prd

azure-client-tools-bot-prd Bot commented Mar 31, 2026

Copy link
Copy Markdown
❌AzureCLI-FullTest
️✔️acr
️✔️latest
️✔️3.12
️✔️3.14
️✔️acs
️✔️latest
️✔️3.12
️✔️3.14
️✔️advisor
️✔️latest
️✔️3.12
️✔️3.14
❌ams
❌latest
❌3.12
Type Test Case Error Message Line
Failed test_ams_sp_create_reset self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f9007ac35c0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f900a746090>
command = 'ams account sp reset-credentials -a ams000003 -g clitest.rg000001 -n ams000003-access-sp -p spp1!000005'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.12/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:153: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/patches.py:33: in handle_main_exception
    raise ex
env/lib/python3.12/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:677: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:820: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:812: in run_job
    return cmd_copy.exception_handler(ex)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/exception_handler.py:16: in ams_exception_handler
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:789: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:335: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/command_operation.py:120: in handler
    return op(**command_args)
           ^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:54: in reset_sp_credentials_for_mediaservice
    assign_role(cmd, entity_name_string="role assignment", role=role, sp_oid=sp_oid, scope=ams.id)
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:245: in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:302: in assign_role
    assignments = list_role_assignments(cmd, sp_oid, scope)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:150: in list_role_assignments
    assignments = search_role_assignments(assignments_client, assignee_object_id)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:296: in search_role_assignments
    assignments = list(assignments_client.list_for_subscription(filter=f))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/paging.py:136: in next
    return next(self.page_iterator)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/paging.py:82: in next
    self.response = self.get_next(self.continuation_token)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/authorization/operations/operations.py:10304: in get_next
    pipeline_response: PipelineResponse = self.client.pipeline.run(  # pylint: disable=protected-access
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:242: in run
    return first_node.send(pipeline_request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/core/policies/base.py:95: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/redirect.py:205: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/retry.py:545: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/authentication.py:194: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:130: in send
    self.sender.send(request.http_request, **request.context.options),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/transport/requests_basic.py:375: in send
    response = self.session.request(  # type: ignore
env/lib/python3.12/site-packages/requests/sessions.py:592: in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/requests/sessions.py:706: in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/requests/adapters.py:645: in send
    resp = conn.urlopen(
env/lib/python3.12/site-packages/urllib3/connectionpool.py:788: in urlopen
    response = self.make_request(
env/lib/python3.12/site-packages/urllib3/connectionpool.py:534: in make_request
    response = conn.getresponse()
               ^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
    

self = <VCRRequestsHTTPSConnection/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/ams/tests/latest/recordings/test_ams_sp_create_reset.yaml(host='management.azure.com', port=443) at 0x7f9007a23d10>
 = False, kwargs = {}

    def getresponse(self, 
=False, **kwargs):
        """Retrieve the response"""
        # Check to see if the cassette has a response for this request. If so,
        # then return it
        if self.cassette.can_play_response_for(self.vcr_request):
            log.info(f"Playing response for {self.vcr_request} from cassette")
            response = self.cassette.play_response(self.vcr_request)
            return VCRHTTPResponse(response, self.vcr_request.uri)
        else:
            if self.cassette.write_protected and self.cassette.filter_request(self.vcr_request):
>               raise CannotOverwriteExistingCassetteException(
                    cassette=self.cassette,
                    failed_request=self.vcr_request,
                )
E               vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/ams/tests/latest/recordings/test_ams_sp_create_reset.yaml') in your current record mode (RecordMode.ONCE: 'once').
E               No match for the request (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId%20eq%20%2727e628bb-89e7-44f6-9193-9c3d4955dcff%27>)&nbsp;was&nbsp;found.
E               Found 2 recorded request(s) matching (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId%20eq%20%2727e628bb-89e7-44f6-9193-9c3d4955dcff%27>)&nbsp;but&nbsp;they&nbsp;have&nbsp;already&nbsp;been&nbsp;consumed.

env/lib/python3.12/site-packages/vcr/stubs/init.py:279: CannotOverwriteExistingCassetteException

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.ams.tests.latest.test_ams_sp_scenarios.AmsSpTests testMethod=test_ams_sp_create_reset>
resource_group = 'clitest.rg000001'
storage_account_for_create = 'clitest000002'

    @ResourceGroupPreparer()
    @StorageAccountPreparer(parameter_name='storage_account_for_create')
    @AllowLargeResponse()
    def test_ams_sp_create_reset(self, resource_group, storage_account_for_create):
        with mock.patch('azure.cli.command_modules.ams.operations.sp.gen_guid', side_effect=self.create_guid):
            amsname = self.create_random_name(prefix='ams', length=12)
    
            self.kwargs.update({
                'amsname': amsname,
                'storageAccount': storage_account_for_create,
                'location': 'westus2'
            })
    
            self.cmd('az ams account create -n {amsname} -g {rg} --storage-account {storageAccount} -l {location}', checks=[
                self.check('name', '{amsname}'),
                self.check('location', 'West US 2')
            ])
    
            spPassword = self.create_random_name(prefix='spp1!', length=16)
            spNewPassword = self.create_random_name(prefix='spp1!', length=16)
    
            self.kwargs.update({
                'spName': '{}-access-sp'.format(amsname),
                'spPassword': spPassword,
                'spNewPassword': spNewPassword,
                'role': 'Owner'
            })
    
            try:
                spjson = self.cmd('az ams account sp create -a {amsname} -n {spName} -g {rg} -p {spPassword} --role {role}', checks=[
                    self.check('AadSecretFriendlyName', '{spPassword}'),
                    self.check('ResourceGroup', '{rg}'),
                    self.check('AccountName', '{amsname}'),
                    self.check('Role', '{role}')
                ]).get_output_in_json()
                self.kwargs.update({'appId': spjson['AadClientId']})
    
                # Wait 2 minutes for role assignment to be created.
                time.sleep(300)
    
>               self.cmd('az ams account sp reset-credentials -a {amsname} -g {rg} -n {spName} -p {spNewPassword}', checks=[
                    self.check('AadClientId', '{appId}'),
                    self.check('AadSecretFriendlyName', '{spNewPassword}'),
                    self.check('ResourceGroup', '{rg}'),
                    self.check('AccountName', '{amsname}')
                ])

src/azure-cli/azure/cli/command_modules/ams/tests/latest/test_ams_sp_scenarios.py:53: 
 
 
 
 
 
 
 
                                 
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
                                       _ 

self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f9007ac35c0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f900a746090>
command = 'ams account sp reset-credentials -a ams000003 -g clitest.rg000001 -n ams000003-access-sp -p spp1!000005'
expect_failure = False

    def _in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
            self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
            self.output = stdout_buf.getvalue()
            self.applog = logging_buf.getvalue()
    
        except CannotOverwriteExistingCassetteException as ex:
>           raise AssertionError(ex)
E           AssertionError: Can't overwrite existing cassette ('/mnt/vss/_work/1/s/src/azure-cli/azure/cli/command_modules/ams/tests/latest/recordings/test_ams_sp_create_reset.yaml') in your current record mode (RecordMode.ONCE: 'once').
E           No match for the request (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId%20eq%20%2727e628bb-89e7-44f6-9193-9c3d4955dcff%27>)&nbsp;was&nbsp;found.
E           Found 2 recorded request(s) matching (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId%20eq%20%2727e628bb-89e7-44f6-9193-9c3d4955dcff%27>)&nbsp;but&nbsp;they&nbsp;have&nbsp;already&nbsp;been&nbsp;consumed.

src/azure-cli-testsdk/azure/cli/testsdk/base.py:308: AssertionError
azure/cli/command_modules/ams/tests/latest/test_ams_sp_scenarios.py:12
❌3.14
Type Test Case Error Message Line
Failed test_ams_sp_create_reset self = <azure.cli.testsdk.base.ExecutionResult object at 0x7efe19898f50>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7efe20223d90>
command = 'ams account sp reset-credentials -a ams000003 -g clitest.rg000001 -n ams000003-access-sp -p spp1!000005'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.14/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:153: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/patches.py:33: in handle_main_exception
    raise ex
env/lib/python3.14/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:677: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:820: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:812: in run_job
    return cmd_copy.exception_handler(ex)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/exception_handler.py:16: in ams_exception_handler
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:789: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:335: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/command_operation.py:120: in handler
    return op(**command_args)
           ^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:54: in reset_sp_credentials_for_mediaservice
    assign_role(cmd, entity_name_string="role assignment", role=role, sp_oid=sp_oid, scope=ams.id)
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:245: in inner
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:302: in assign_role
    assignments = list_role_assignments(cmd, sp_oid, scope)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:150: in list_role_assignments
    assignments = search_role_assignments(assignments_client, assignee_object_id)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/ams/operations/sp.py:296: in search_role_assignments
    assignments = list(assignments_client.list_for_subscription(filter=f))
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/paging.py:136: in next
    return next(self.page_iterator)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/paging.py:82: in next
    self.response = self.get_next(self.continuation_token)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/mgmt/authorization/operations/operations.py:10304: in get_next
    pipeline_response: PipelineResponse = self.client.pipeline.run(  # pylint: disable=protected-access
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:242: in run
    return first_node.send(pipeline_request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/mgmt/core/policies/base.py:95: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/policies/redirect.py:205: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/policies/retry.py:545: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/policies/authentication.py:194: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:130: in send
    self.sender.send(request.http_request, **request.context.options),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/transport/requests_basic.py:375: in send
    response = self.session.request(  # type: ignore
env/lib/python3.14/site-packages/requests/sessions.py:592: in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/requests/sessions.py:706: in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/requests/adapters.py:645: in send
    resp = conn.urlopen(
env/lib/python3.14/site-packages/urllib3/connectionpool.py:788: in urlopen
    response = self.make_request(
env/lib/python3.14/site-packages/urllib3/connectionpool.py:534: in make_request
    response = conn.getresponse()
               ^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
    

self = <VCRRequestsHTTPSConnection/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/ams/tests/latest/recordings/test_ams_sp_create_reset.yaml(host='management.azure.com', port=443) at 0x7efe19796900>
 = False, kwargs = {}

    def getresponse(self, 
=False, **kwargs):
        """Retrieve the response"""
        # Check to see if the cassette has a response for this request. If so,
        # then return it
        if self.cassette.can_play_response_for(self.vcr_request):
            log.info(f"Playing response for {self.vcr_request} from cassette")
            response = self.cassette.play_response(self.vcr_request)
            return VCRHTTPResponse(response, self.vcr_request.uri)
        else:
            if self.cassette.write_protected and self.cassette.filter_request(self.vcr_request):
>               raise CannotOverwriteExistingCassetteException(
                    cassette=self.cassette,
                    failed_request=self.vcr_request,
                )
E               vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/ams/tests/latest/recordings/test_ams_sp_create_reset.yaml') in your current record mode (RecordMode.ONCE: 'once').
E               No match for the request (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId%20eq%20%2727e628bb-89e7-44f6-9193-9c3d4955dcff%27>)&nbsp;was&nbsp;found.
E               Found 2 recorded request(s) matching (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId%20eq%20%2727e628bb-89e7-44f6-9193-9c3d4955dcff%27>)&nbsp;but&nbsp;they&nbsp;have&nbsp;already&nbsp;been&nbsp;consumed.

env/lib/python3.14/site-packages/vcr/stubs/init.py:279: CannotOverwriteExistingCassetteException

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.ams.tests.latest.test_ams_sp_scenarios.AmsSpTests testMethod=test_ams_sp_create_reset>
resource_group = 'clitest.rg000001'
storage_account_for_create = 'clitest000002'

    @ResourceGroupPreparer()
    @StorageAccountPreparer(parameter_name='storage_account_for_create')
    @AllowLargeResponse()
    def test_ams_sp_create_reset(self, resource_group, storage_account_for_create):
        with mock.patch('azure.cli.command_modules.ams.operations.sp.gen_guid', side_effect=self.create_guid):
            amsname = self.create_random_name(prefix='ams', length=12)
    
            self.kwargs.update({
                'amsname': amsname,
                'storageAccount': storage_account_for_create,
                'location': 'westus2'
            })
    
            self.cmd('az ams account create -n {amsname} -g {rg} --storage-account {storageAccount} -l {location}', checks=[
                self.check('name', '{amsname}'),
                self.check('location', 'West US 2')
            ])
    
            spPassword = self.create_random_name(prefix='spp1!', length=16)
            spNewPassword = self.create_random_name(prefix='spp1!', length=16)
    
            self.kwargs.update({
                'spName': '{}-access-sp'.format(amsname),
                'spPassword': spPassword,
                'spNewPassword': spNewPassword,
                'role': 'Owner'
            })
    
            try:
                spjson = self.cmd('az ams account sp create -a {amsname} -n {spName} -g {rg} -p {spPassword} --role {role}', checks=[
                    self.check('AadSecretFriendlyName', '{spPassword}'),
                    self.check('ResourceGroup', '{rg}'),
                    self.check('AccountName', '{amsname}'),
                    self.check('Role', '{role}')
                ]).get_output_in_json()
                self.kwargs.update({'appId': spjson['AadClientId']})
    
                # Wait 2 minutes for role assignment to be created.
                time.sleep(300)
    
>               self.cmd('az ams account sp reset-credentials -a {amsname} -g {rg} -n {spName} -p {spNewPassword}', checks=[
                    self.check('AadClientId', '{appId}'),
                    self.check('AadSecretFriendlyName', '{spNewPassword}'),
                    self.check('ResourceGroup', '{rg}'),
                    self.check('AccountName', '{amsname}')
                ])

src/azure-cli/azure/cli/command_modules/ams/tests/latest/test_ams_sp_scenarios.py:53: 
 
 
 
 
 
 
 
                                 
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
                                       _ 

self = <azure.cli.testsdk.base.ExecutionResult object at 0x7efe19898f50>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7efe20223d90>
command = 'ams account sp reset-credentials -a ams000003 -g clitest.rg000001 -n ams000003-access-sp -p spp1!000005'
expect_failure = False

    def _in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
            self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
            self.output = stdout_buf.getvalue()
            self.applog = logging_buf.getvalue()
    
        except CannotOverwriteExistingCassetteException as ex:
>           raise AssertionError(ex)
E           AssertionError: Can't overwrite existing cassette ('/mnt/vss/_work/1/s/src/azure-cli/azure/cli/command_modules/ams/tests/latest/recordings/test_ams_sp_create_reset.yaml') in your current record mode (RecordMode.ONCE: 'once').
E           No match for the request (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId%20eq%20%2727e628bb-89e7-44f6-9193-9c3d4955dcff%27>)&nbsp;was&nbsp;found.
E           Found 2 recorded request(s) matching (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/providers/Microsoft.Authorization/roleAssignments?api-version=2022-04-01&$filter=principalId%20eq%20%2727e628bb-89e7-44f6-9193-9c3d4955dcff%27>)&nbsp;but&nbsp;they&nbsp;have&nbsp;already&nbsp;been&nbsp;consumed.

src/azure-cli-testsdk/azure/cli/testsdk/base.py:308: AssertionError
azure/cli/command_modules/ams/tests/latest/test_ams_sp_scenarios.py:12
️✔️apim
️✔️latest
️✔️3.12
️✔️3.14
️✔️appconfig
️✔️latest
️✔️3.12
️✔️3.14
️✔️appservice
️✔️latest
️✔️3.12
️✔️3.14
❌aro
❌latest
❌3.12
Type Test Case Error Message Line
Failed test_aro_public_cluster self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f455dcce6f0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f45603e53a0>
command = 'aro validate -g cli_test_aro000001 -n aro000005 --client-id 00000000-0000-0000-0000-000000000001 --client-secret fake...icrosoft.Network/virtualNetworks/dev-vnet/subnets/dev_worker000004 --subscription 00000000-0000-0000-0000-000000000000'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.12/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:153: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/patches.py:33: in handle_main_exception
    raise ex
env/lib/python3.12/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:677: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:820: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:789: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:335: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/command_operation.py:120: in handler
    return op(**command_args)
           ^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/aro/custom.py:359: in aro_validate
    validate(cmd=cmd,
src/azure-cli/azure/cli/command_modules/aro/custom.py:327: in validate
    error_obj = error_func(cmd, namespace)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/aro/dynamic_validators.py:127: in inner
    errors = func(cmd, namespace)
             ^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/aro/dynamic_validators.py:156: in validate_vnet
    errors = validate_resource(auth_client, key, parts, [
src/azure-cli/azure/cli/command_modules/aro/dynamic_validators.py:69: in validate_resource
    perms_list = list(perms_copy)
                 ^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/paging.py:136: in next
    return next(self.page_iterator)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/paging.py:82: in next
    self.response = self.get_next(self.continuation_token)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/authorization/operations/operations.py:16115: in get_next
    pipeline_response: PipelineResponse = self.client.pipeline.run(  # pylint: disable=protected-access
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:242: in run
    return first_node.send(pipeline_request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/core/policies/base.py:95: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/redirect.py:205: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/retry.py:545: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/policies/authentication.py:194: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/base.py:130: in send
    self.sender.send(request.http_request, **request.context.options),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/core/pipeline/transport/requests_basic.py:375: in send
    response = self.session.request(  # type: ignore
env/lib/python3.12/site-packages/requests/sessions.py:592: in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/requests/sessions.py:706: in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/requests/adapters.py:645: in send
    resp = conn.urlopen(
env/lib/python3.12/site-packages/urllib3/connectionpool.py:788: in urlopen
    response = self.make_request(
env/lib/python3.12/site-packages/urllib3/connectionpool.py:534: in make_request
    response = conn.getresponse()
               ^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      

self = <VCRRequestsHTTPSConnection/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/aro/tests/latest/recordings/test_aro_public_cluster.yaml(host='management.azure.com', port=443) at 0x7f455dbb0290>
 = False, kwargs = {}

    def getresponse(self, 
=False, **kwargs):
        """Retrieve the response"""
        # Check to see if the cassette has a response for this request. If so,
        # then return it
        if self.cassette.can_play_response_for(self.vcr_request):
            log.info(f"Playing response for {self.vcr_request} from cassette")
            response = self.cassette.play_response(self.vcr_request)
            return VCRHTTPResponse(response, self.vcr_request.uri)
        else:
            if self.cassette.write_protected and self.cassette.filter_request(self.vcr_request):
>               raise CannotOverwriteExistingCassetteException(
                    cassette=self.cassette,
                    failed_request=self.vcr_request,
                )
E               vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/aro/tests/latest/recordings/test_aro_public_cluster.yaml') in your current record mode (RecordMode.ONCE: 'once').
E               No match for the request (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network//virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>) was found.
E               Found 2 similar requests with 1 different matcher(s) :
E               
E               1 - (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>).
E               Matchers succeeded : ['method', 'scheme', 'host', 'port', 'custom_request_query_matcher']
E               Matchers failed :
E               path - assertion failure :
E               /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions != /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions
E               
E               2 - (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>).
E               Matchers succeeded : ['method', 'scheme', 'host', 'port', 'custom_request_query_matcher']
E               Matchers failed :
E               path - assertion failure :
E               /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions != /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions

env/lib/python3.12/site-packages/vcr/stubs/init.py:279: CannotOverwriteExistingCassetteException

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.aro.tests.latest.test_aro_scenario.AroScenarioTests testMethod=test_aro_public_cluster>
resource_group = 'cli_test_aro000001'

    @AllowLargeResponse()
    @ResourceGroupPreparer(random_name_length=28, name_prefix='cli_test_aro', location='eastus')
    @AROClusterServicePrincipalPreparer(name_prefix='cli_test_aro')
    def test_aro_public_cluster(self, resource_group):
        from azure.mgmt.core.tools import resource_id
    
        subscription = self.get_subscription_id()
    
        master_subnet = self.create_random_name('dev_master', 14)
        worker_subnet = self.create_random_name('dev_worker', 14)
        name = self.create_random_name('aro', 14)
    
        temp_kubeconfig_path = self.create_random_name('kubeconfig', 24) + '.tmp'
    
        self.kwargs.update({
            'name': name,
            'resource_group': resource_group,
            'subscription': subscription,
            'master_subnet': master_subnet,
            'worker_subnet': worker_subnet,
            'master_ip_range': '10.{}.{}.0/24'.format(randint(0, 127), randint(0, 255)),
            'worker_ip_range': '10.{}.{}.0/24'.format(randint(0, 127), randint(0, 255)),
            'master_subnet_resource': resource_id(subscription=subscription, resource_group=resource_group, namespace='Microsoft.Network', type='virtualNetworks', child_type_1='subnets', name='dev-vnet', child_name_1=master_subnet),
            'worker_subnet_resource': resource_id(subscription=subscription, resource_group=resource_group, namespace='Microsoft.Network', type='virtualNetworks', child_type_1='subnets', name='dev-vnet', child_name_1=worker_subnet),
            'temp_kubeconfig_path': temp_kubeconfig_path,
        })
    
        self.cmd('network vnet create -g {rg} -n dev-vnet --address-prefixes 10.0.0.0/9')
        self.cmd('network vnet subnet create -g {rg} --vnet-name dev-vnet -n {master_subnet} --address-prefixes {master_ip_range} --service-endpoints Microsoft.ContainerRegistry --default-outbound false')
        self.cmd('network vnet subnet create -g {rg} --vnet-name dev-vnet -n {worker_subnet} --address-prefixes {worker_ip_range} --service-endpoints Microsoft.ContainerRegistry --default-outbound false')
        self.cmd('network vnet subnet update -g {rg} --vnet-name dev-vnet -n {master_subnet} --private-link-service-network-policies Disabled')
    
        # aro validate
        with mock.patch('azure.cli.command_modules.aro.rbac.gen_uuid', side_effect=self.create_guid):
>           self.cmd('aro validate -g {rg} -n {name} --client-id {aro_csp} --client-secret {aro_csp_pass} --master-subnet {master_subnet_resource} --worker-subnet {worker_subnet_resource} --subscription {subscription}')

src/azure-cli/azure/cli/command_modules/aro/tests/latest/test_aro_scenario.py:73: 
 
 
 
 
 
 
 
 
 
 
                              
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
 
                                       

self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f455dcce6f0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f45603e53a0>
command = 'aro validate -g cli_test_aro000001 -n aro000005 --client-id 00000000-0000-0000-0000-000000000001 --client-secret fake...icrosoft.Network/virtualNetworks/dev-vnet/subnets/dev_worker000004 --subscription 00000000-0000-0000-0000-000000000000'
expect_failure = False

    def _in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
            self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
            self.output = stdout_buf.getvalue()
            self.applog = logging_buf.getvalue()
    
        except CannotOverwriteExistingCassetteException as ex:
>           raise AssertionError(ex)
E           AssertionError: Can't overwrite existing cassette ('/mnt/vss/_work/1/s/src/azure-cli/azure/cli/command_modules/aro/tests/latest/recordings/test_aro_public_cluster.yaml') in your current record mode (RecordMode.ONCE: 'once').
E           No match for the request (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network//virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>) was found.
E           Found 2 similar requests with 1 different matcher(s) :
E           
E           1 - (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>).
E           Matchers succeeded : ['method', 'scheme', 'host', 'port', '_custom_request_query_matcher']
E           Matchers failed :
E           path - assertion failure :
E           /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions != /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions
E           
E           2 - (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>).
E           Matchers succeeded : ['method', 'scheme', 'host', 'port', '_custom_request_query_matcher']
E           Matchers failed :
E           path - assertion failure :
E           /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions != /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions

src/azure-cli-testsdk/azure/cli/testsdk/base.py:308: AssertionError
azure/cli/command_modules/aro/tests/latest/test_aro_scenario.py:38
❌3.14
Type Test Case Error Message Line
Failed test_aro_public_cluster self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f3003f456e0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f3005f13ed0>
command = 'aro validate -g cli_test_aro000001 -n aro000005 --client-id 00000000-0000-0000-0000-000000000001 --client-secret fake...icrosoft.Network/virtualNetworks/dev-vnet/subnets/dev_worker000004 --subscription 00000000-0000-0000-0000-000000000000'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.14/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:153: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/patches.py:33: in handle_main_exception
    raise ex
env/lib/python3.14/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:677: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:820: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:789: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:335: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/command_operation.py:120: in handler
    return op(**command_args)
           ^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/aro/custom.py:359: in aro_validate
    validate(cmd=cmd,
src/azure-cli/azure/cli/command_modules/aro/custom.py:327: in validate
    error_obj = error_func(cmd, namespace)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/aro/dynamic_validators.py:127: in inner
    errors = func(cmd, namespace)
             ^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/aro/dynamic_validators.py:156: in validate_vnet
    errors = validate_resource(auth_client, key, parts, [
src/azure-cli/azure/cli/command_modules/aro/dynamic_validators.py:69: in validate_resource
    perms_list = list(perms_copy)
                 ^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/paging.py:136: in next
    return next(self.page_iterator)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/paging.py:82: in next
    self.response = self.get_next(self.continuation_token)
                     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/mgmt/authorization/operations/operations.py:16115: in get_next
    pipeline_response: PipelineResponse = self.client.pipeline.run(  # pylint: disable=protected-access
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:242: in run
    return first_node.send(pipeline_request)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/mgmt/core/policies/base.py:95: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/policies/redirect.py:205: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/policies/retry.py:545: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/policies/authentication.py:194: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:98: in send
    response = self.next.send(request)
               ^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/base.py:130: in send
    self.sender.send(request.http_request, **request.context.options),
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/core/pipeline/transport/requests_basic.py:375: in send
    response = self.session.request(  # type: ignore
env/lib/python3.14/site-packages/requests/sessions.py:592: in request
    resp = self.send(prep, **send_kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/requests/sessions.py:706: in send
    r = adapter.send(request, **kwargs)
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/requests/adapters.py:645: in send
    resp = conn.urlopen(
env/lib/python3.14/site-packages/urllib3/connectionpool.py:788: in urlopen
    response = self.make_request(
env/lib/python3.14/site-packages/urllib3/connectionpool.py:534: in make_request
    response = conn.getresponse()
               ^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
      

self = <VCRRequestsHTTPSConnection/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/aro/tests/latest/recordings/test_aro_public_cluster.yaml(host='management.azure.com', port=443) at 0x7f3003cbfcb0>
 = False, kwargs = {}

    def getresponse(self, 
=False, **kwargs):
        """Retrieve the response"""
        # Check to see if the cassette has a response for this request. If so,
        # then return it
        if self.cassette.can_play_response_for(self.vcr_request):
            log.info(f"Playing response for {self.vcr_request} from cassette")
            response = self.cassette.play_response(self.vcr_request)
            return VCRHTTPResponse(response, self.vcr_request.uri)
        else:
            if self.cassette.write_protected and self.cassette.filter_request(self.vcr_request):
>               raise CannotOverwriteExistingCassetteException(
                    cassette=self.cassette,
                    failed_request=self.vcr_request,
                )
E               vcr.errors.CannotOverwriteExistingCassetteException: Can't overwrite existing cassette ('/mnt/vss/work/1/s/src/azure-cli/azure/cli/command_modules/aro/tests/latest/recordings/test_aro_public_cluster.yaml') in your current record mode (RecordMode.ONCE: 'once').
E               No match for the request (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network//virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>) was found.
E               Found 2 similar requests with 1 different matcher(s) :
E               
E               1 - (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>).
E               Matchers succeeded : ['method', 'scheme', 'host', 'port', 'custom_request_query_matcher']
E               Matchers failed :
E               path - assertion failure :
E               /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions != /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions
E               
E               2 - (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>).
E               Matchers succeeded : ['method', 'scheme', 'host', 'port', 'custom_request_query_matcher']
E               Matchers failed :
E               path - assertion failure :
E               /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions != /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions

env/lib/python3.14/site-packages/vcr/stubs/init.py:279: CannotOverwriteExistingCassetteException

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.aro.tests.latest.test_aro_scenario.AroScenarioTests testMethod=test_aro_public_cluster>
resource_group = 'cli_test_aro000001'

    @AllowLargeResponse()
    @ResourceGroupPreparer(random_name_length=28, name_prefix='cli_test_aro', location='eastus')
    @AROClusterServicePrincipalPreparer(name_prefix='cli_test_aro')
    def test_aro_public_cluster(self, resource_group):
        from azure.mgmt.core.tools import resource_id
    
        subscription = self.get_subscription_id()
    
        master_subnet = self.create_random_name('dev_master', 14)
        worker_subnet = self.create_random_name('dev_worker', 14)
        name = self.create_random_name('aro', 14)
    
        temp_kubeconfig_path = self.create_random_name('kubeconfig', 24) + '.tmp'
    
        self.kwargs.update({
            'name': name,
            'resource_group': resource_group,
            'subscription': subscription,
            'master_subnet': master_subnet,
            'worker_subnet': worker_subnet,
            'master_ip_range': '10.{}.{}.0/24'.format(randint(0, 127), randint(0, 255)),
            'worker_ip_range': '10.{}.{}.0/24'.format(randint(0, 127), randint(0, 255)),
            'master_subnet_resource': resource_id(subscription=subscription, resource_group=resource_group, namespace='Microsoft.Network', type='virtualNetworks', child_type_1='subnets', name='dev-vnet', child_name_1=master_subnet),
            'worker_subnet_resource': resource_id(subscription=subscription, resource_group=resource_group, namespace='Microsoft.Network', type='virtualNetworks', child_type_1='subnets', name='dev-vnet', child_name_1=worker_subnet),
            'temp_kubeconfig_path': temp_kubeconfig_path,
        })
    
        self.cmd('network vnet create -g {rg} -n dev-vnet --address-prefixes 10.0.0.0/9')
        self.cmd('network vnet subnet create -g {rg} --vnet-name dev-vnet -n {master_subnet} --address-prefixes {master_ip_range} --service-endpoints Microsoft.ContainerRegistry --default-outbound false')
        self.cmd('network vnet subnet create -g {rg} --vnet-name dev-vnet -n {worker_subnet} --address-prefixes {worker_ip_range} --service-endpoints Microsoft.ContainerRegistry --default-outbound false')
        self.cmd('network vnet subnet update -g {rg} --vnet-name dev-vnet -n {master_subnet} --private-link-service-network-policies Disabled')
    
        # aro validate
        with mock.patch('azure.cli.command_modules.aro.rbac.gen_uuid', side_effect=self.create_guid):
>           self.cmd('aro validate -g {rg} -n {name} --client-id {aro_csp} --client-secret {aro_csp_pass} --master-subnet {master_subnet_resource} --worker-subnet {worker_subnet_resource} --subscription {subscription}')

src/azure-cli/azure/cli/command_modules/aro/tests/latest/test_aro_scenario.py:73: 
 
 
 
 
 
 
 
 
 
 
                              
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
 
                                       

self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f3003f456e0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f3005f13ed0>
command = 'aro validate -g cli_test_aro000001 -n aro000005 --client-id 00000000-0000-0000-0000-000000000001 --client-secret fake...icrosoft.Network/virtualNetworks/dev-vnet/subnets/dev_worker000004 --subscription 00000000-0000-0000-0000-000000000000'
expect_failure = False

    def _in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
            self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
            self.output = stdout_buf.getvalue()
            self.applog = logging_buf.getvalue()
    
        except CannotOverwriteExistingCassetteException as ex:
>           raise AssertionError(ex)
E           AssertionError: Can't overwrite existing cassette ('/mnt/vss/_work/1/s/src/azure-cli/azure/cli/command_modules/aro/tests/latest/recordings/test_aro_public_cluster.yaml') in your current record mode (RecordMode.ONCE: 'once').
E           No match for the request (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network//virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>) was found.
E           Found 2 similar requests with 1 different matcher(s) :
E           
E           1 - (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>).
E           Matchers succeeded : ['method', 'scheme', 'host', 'port', '_custom_request_query_matcher']
E           Matchers failed :
E           path - assertion failure :
E           /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions != /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions
E           
E           2 - (<Request (GET) https://management.azure.com/subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions?api-version=2022-05-01-preview>).
E           Matchers succeeded : ['method', 'scheme', 'host', 'port', '_custom_request_query_matcher']
E           Matchers failed :
E           path - assertion failure :
E           /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions != /subscriptions/00000000-0000-0000-0000-000000000000/resourcegroups/cli_test_aro000001/providers/Microsoft.Network/virtualNetworks/dev-vnet/providers/Microsoft.Authorization/permissions

src/azure-cli-testsdk/azure/cli/testsdk/base.py:308: AssertionError
azure/cli/command_modules/aro/tests/latest/test_aro_scenario.py:38
️✔️backup
️✔️latest
️✔️3.12
️✔️3.14
️✔️batch
️✔️latest
️✔️3.12
️✔️3.14
️✔️batchai
️✔️latest
️✔️3.12
️✔️3.14
️✔️billing
️✔️latest
️✔️3.12
️✔️3.14
️✔️botservice
️✔️latest
️✔️3.12
️✔️3.14
️✔️cdn
️✔️latest
️✔️3.12
️✔️3.14
️✔️cloud
️✔️latest
️✔️3.12
️✔️3.14
️✔️cognitiveservices
️✔️latest
️✔️3.12
️✔️3.14
️✔️compute_recommender
️✔️latest
️✔️3.12
️✔️3.14
️✔️computefleet
️✔️latest
️✔️3.12
️✔️3.14
️✔️config
️✔️latest
️✔️3.12
️✔️3.14
️✔️configure
️✔️latest
️✔️3.12
️✔️3.14
️✔️consumption
️✔️latest
️✔️3.12
️✔️3.14
️✔️container
️✔️latest
️✔️3.12
️✔️3.14
️✔️containerapp
️✔️latest
️✔️3.12
️✔️3.14
️✔️core
️✔️latest
️✔️3.12
️✔️3.14
️✔️cosmosdb
️✔️latest
️✔️3.12
️✔️3.14
️✔️databoxedge
️✔️latest
️✔️3.12
️✔️3.14
️✔️dls
️✔️latest
️✔️3.12
️✔️3.14
️✔️dms
️✔️latest
️✔️3.12
️✔️3.14
️✔️eventgrid
️✔️latest
️✔️3.12
️✔️3.14
️✔️eventhubs
️✔️latest
️✔️3.12
️✔️3.14
️✔️feedback
️✔️latest
️✔️3.12
️✔️3.14
️✔️find
️✔️latest
️✔️3.12
️✔️3.14
️✔️hdinsight
️✔️latest
️✔️3.12
️✔️3.14
️✔️identity
️✔️latest
️✔️3.12
️✔️3.14
️✔️iot
️✔️latest
️✔️3.12
️✔️3.14
️✔️keyvault
️✔️latest
️✔️3.12
️✔️3.14
️✔️lab
️✔️latest
️✔️3.12
️✔️3.14
️✔️managedservices
️✔️latest
️✔️3.12
️✔️3.14
️✔️maps
️✔️latest
️✔️3.12
️✔️3.14
️✔️marketplaceordering
️✔️latest
️✔️3.12
️✔️3.14
️✔️monitor
️✔️latest
️✔️3.12
️✔️3.14
️✔️mysql
️✔️latest
️✔️3.12
️✔️3.14
️✔️netappfiles
️✔️latest
️✔️3.12
️✔️3.14
️✔️network
️✔️latest
️✔️3.12
️✔️3.14
️✔️policyinsights
️✔️latest
️✔️3.12
️✔️3.14
️✔️postgresql
️✔️latest
️✔️3.12
️✔️3.14
️✔️privatedns
️✔️latest
️✔️3.12
️✔️3.14
️✔️profile
️✔️latest
️✔️3.12
️✔️3.14
️✔️rdbms
️✔️latest
️✔️3.12
️✔️3.14
️✔️redis
️✔️latest
️✔️3.12
️✔️3.14
️✔️relay
️✔️latest
️✔️3.12
️✔️3.14
❌resource
❌latest
❌3.12
Type Test Case Error Message Line
Failed test_resource_policy_identity self = <azure.cli.testsdk.base.ExecutionResult object at 0x7fdfb7e023f0>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7fdfbbeabaa0>
command = 'policy assignment create --policy 06a78e20-9358-41c9-923c-fb736d382a4d -n azurecli-test-policy-assignment000002 -g cl...-scope /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_policy_identity000001 --role Reader'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.12/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:153: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
                                        

ex = TypeError('Object of type AAZSimpleValue is not JSON serializable')
args = (), kwargs = {}

    def handle_main_exception(ex, *args, **kwargs):  # pylint: disable=unused-argument
        if isinstance(ex, CannotOverwriteExistingCassetteException):
            # This exception usually caused by a no match HTTP request. This is a product error
            # that is caused by change of SDK invocation.
            raise ex
    
>       raise CliExecutionError(ex)
E       azure.cli.testsdk.exceptions.CliExecutionError: The CLI throws exception TypeError during execution and fails the command.

src/azure-cli-testsdk/azure/cli/testsdk/patches.py:35: CliExecutionError

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.resource.tests.latest.test_resource.PolicyScenarioTest testMethod=test_resource_policy_identity>
resource_group = 'cli_test_policy_identity000001'
resource_group_location = 'westus'

    @ResourceGroupPreparer(name_prefix='cli_test_policy_identity')
    @AllowLargeResponse(8192)
    def test_resource_policy_identity(self, resource_group, resource_group_location):
        self.kwargs.update({
            'pan': self.create_random_name('azurecli-test-policy-assignment', 40),
            'bip': '06a78e20-9358-41c9-923c-fb736d382a4d',
            'sub': self.get_subscription_id(),
            'location': resource_group_location,
            'em': 'DoNotEnforce'
        })
    
        with self.assertRaises(InvalidArgumentValueError):
            self.cmd('policy assignment create --policy 'test/error_policy' -n {pan} -g {rg} --location {location} --assign-identity --enforcement-mode {em}')
    
        # create a policy assignment with managed identity using a built in policy definition
        assignmentIdentity = self.cmd('policy assignment create --policy {bip} -n {pan} -g {rg} --location {location} --assign-identity --enforcement-mode {em}', checks=[
            self.check('name', '{pan}'),
            self.check('location', '{location}'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ]).get_output_in_json()['identity']
    
        # ensure managed identity details are retrievable directly through 'policy assignment identity' commands
        self.cmd('policy assignment identity show -n {pan} -g {rg}', checks=[
            self.check('type', assignmentIdentity['type']),
            self.check('principalId', assignmentIdentity['principalId']),
            self.check('tenantId', assignmentIdentity['tenantId'])
        ])
    
        # ensure the managed identity is not touched during update
        self.cmd('policy assignment update -n {pan} -g {rg} --description "New description"', checks=[
            self.check('description', 'New description'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ])
    
        # remove the managed identity and ensure it is removed when retrieving the policy assignment
        self.cmd('policy assignment identity remove -n {pan} -g {rg}', checks=[
            self.check('type', 'None')
        ])
        self.cmd('policy assignment show -n {pan} -g {rg}', checks=[
            self.check('name', '{pan}'),
            self.check('identity.type', 'None')
        ])
    
        # add an identity using 'identity assign'
        self.cmd('policy assignment identity assign -n {pan} -g {rg}', checks=[
            self.check('type', 'SystemAssigned'),
            self.exists('principalId'),
            self.exists('tenantId')
        ])
        self.cmd('policy assignment show -n {pan} -g {rg}', checks=[
            self.check('name', '{pan}'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ])
    
        self.cmd('policy assignment identity remove -n {pan} -g {rg}', checks=[
            self.check('type', 'None')
        ])
    
        # create a role assignment for the identity using --assign-identity
        self.kwargs.update({
            'idScope': '/subscriptions/{sub}/resourceGroups/{rg}'.format(**self.kwargs),
            'idRole': 'Reader'
        })
        with mock.patch('azure.cli.core.commands.arm.gen_guid', side_effect=self.create_guid):
>           assignmentIdentity = self.cmd('policy assignment create --policy {bip} -n {pan} -g {rg} --location {location} --assign-identity --identity-scope {idScope} --role {idRole}', checks=[
                self.check('name', '{pan}'),
                self.check('location', '{location}'),
                self.check('identity.type', 'SystemAssigned'),
                self.exists('identity.principalId'),
                self.exists('identity.tenantId')
            ]).get_output_in_json()['identity']

src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py:4114: 
 
 
                                      
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
src/azure-cli-testsdk/azure/cli/testsdk/base.py:315: in in_process_execute
    raise ex.exception
env/lib/python3.12/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:677: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:820: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:789: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/aaz/command.py:154: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/resource/aaz/latest/policy/assignment/create.py:50: in handler
    self.execute_operations()
src/azure-cli/azure/cli/command_modules/resource/policy.py:363: in execute_operations
    self.post_operations()
src/azure-cli/azure/cli/command_modules/resource/policy.py:366: in post_operations
    Common.CreateRoleAssignment(self.ctx, self.cli_ctx, self.ctx.vars.instance)
src/azure-cli/azure/cli/command_modules/resource/policy.py:112: in CreateRoleAssignment
    assign_identity(
src/azure-cli-core/azure/cli/core/commands/arm.py:768: in assign_identity
    create_role_assignment(cli_ctx, principal_id, identity_role, identity_scope)
src/azure-cli-core/azure/cli/core/commands/arm.py:790: in create_role_assignment
    assignments_client.create(scope=identity_scope, role_assignment_name=assignment_name,
env/lib/python3.12/site-packages/azure/core/tracing/decorator.py:119: in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/authorization/operations/operations.py:10004: in create
    content = json.dumps(parameters, cls=SdkJSONEncoder, exclude_readonly=True)  # type: ignore
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/json/init.py:238: in dumps
    **kw).encode(obj)
          ^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/json/encoder.py:200: in encode
    chunks = self.iterencode(o, one_shot=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/json/encoder.py:258: in iterencode
    return iterencode(o, 0)
           ^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/authorization/utils/model_base.py:166: in default
    return super(SdkJSONEncoder, self).default(o)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                       _ 

self = <azure.mgmt.authorization._utils.model_base.SdkJSONEncoder object at 0x7fdfb764f860>
o = '5ce0ff0d-b4af-49f8-8f81-eb5e8cc665d2'

    def default(self, o):
        """Implement this method in a subclass such that it returns
        a serializable object for o, or calls the base implementation
        (to raise a TypeError).
    
        For example, to support arbitrary iterators, you could
        implement default like this::
    
            def default(self, o):
                try:
                    iterable = iter(o)
                except TypeError:
                    pass
                else:
                    return list(iterable)
                # Let the base class default method raise the TypeError
                return super().default(o)
    
        """
>       raise TypeError(f'Object of type {o.class.name} '
                        f'is not JSON serializable')
E       TypeError: Object of type AAZSimpleValue is not JSON serializable

/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/json/encoder.py:180: TypeError
azure/cli/command_modules/resource/tests/latest/test_resource.py:4043
Failed test_resource_policy_identity_systemassigned self = <azure.cli.testsdk.base.ExecutionResult object at 0x7fdfb7b06870>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7fdfbbebe5d0>
command = 'policy assignment create --policy 06a78e20-9358-41c9-923c-fb736d382a4d -n azurecli-test-policy-assignment000002 -g cl...ptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_policy_identity_systemassigned000001 --role Reader'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.12/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:153: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
                                        

ex = TypeError('Object of type AAZSimpleValue is not JSON serializable')
args = (), kwargs = {}

    def handle_main_exception(ex, *args, **kwargs):  # pylint: disable=unused-argument
        if isinstance(ex, CannotOverwriteExistingCassetteException):
            # This exception usually caused by a no match HTTP request. This is a product error
            # that is caused by change of SDK invocation.
            raise ex
    
>       raise CliExecutionError(ex)
E       azure.cli.testsdk.exceptions.CliExecutionError: The CLI throws exception TypeError during execution and fails the command.

src/azure-cli-testsdk/azure/cli/testsdk/patches.py:35: CliExecutionError

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.resource.tests.latest.test_resource.PolicyScenarioTest testMethod=test_resource_policy_identity_systemassigned>
resource_group = 'cli_test_policy_identity_systemassigned000001'
resource_group_location = 'westus'

    @ResourceGroupPreparer(name_prefix='cli_test_policy_identity_systemassigned')
    @AllowLargeResponse(8192)
    def test_resource_policy_identity_systemassigned(self, resource_group, resource_group_location):
        self.kwargs.update({
            'pan': self.create_random_name('azurecli-test-policy-assignment', 40),
            'bip': '06a78e20-9358-41c9-923c-fb736d382a4d',
            'sub': self.get_subscription_id(),
            'location': resource_group_location,
            'em': 'DoNotEnforce'
        })
    
        # create a policy assignment with managed identity using a built in policy definition
        assignmentIdentity = self.cmd('policy assignment create --policy {bip} -n {pan} -g {rg} --location {location} --mi-system-assigned --enforcement-mode {em}', checks=[
            self.check('name', '{pan}'),
            self.check('location', '{location}'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ]).get_output_in_json()['identity']
    
        # ensure managed identity details are retrievable directly through 'policy assignment identity' commands
        self.cmd('policy assignment identity show -n {pan} -g {rg}', checks=[
            self.check('type', assignmentIdentity['type']),
            self.check('principalId', assignmentIdentity['principalId']),
            self.check('tenantId', assignmentIdentity['tenantId'])
        ])
    
        # ensure the managed identity is not touched during update
        self.cmd('policy assignment update -n {pan} -g {rg} --description "New description"', checks=[
            self.check('description', 'New description'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ])
    
        # remove the managed identity and ensure it is removed when retrieving the policy assignment
        self.cmd('policy assignment identity remove -n {pan} -g {rg}', checks=[
            self.check('type', 'None')
        ])
        self.cmd('policy assignment show -n {pan} -g {rg}', checks=[
            self.check('name', '{pan}'),
            self.check('identity.type', 'None')
        ])
    
        # add an identity using 'identity assign'
        self.cmd('policy assignment identity assign --system-assigned -n {pan} -g {rg}', checks=[
            self.check('type', 'SystemAssigned'),
            self.exists('principalId'),
            self.exists('tenantId')
        ])
        self.cmd('policy assignment show -n {pan} -g {rg}', checks=[
            self.check('name', '{pan}'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ])
    
        self.cmd('policy assignment identity remove -n {pan} -g {rg}', checks=[
            self.check('type', 'None')
        ])
    
        # create a role assignment for the identity using --mi-system-assigned
        self.kwargs.update({
            'idScope': '/subscriptions/{sub}/resourceGroups/{rg}'.format(**self.kwargs),
            'idRole': 'Reader'
        })
        with mock.patch('azure.cli.core.commands.arm.gen_guid', side_effect=self.create_guid):
>           assignmentIdentity = self.cmd('policy assignment create --policy {bip} -n {pan} -g {rg} --location {location} --mi-system-assigned --identity-scope {idScope} --role {idRole}', checks=[
                self.check('name', '{pan}'),
                self.check('location', '{location}'),
                self.check('identity.type', 'SystemAssigned'),
                self.exists('identity.principalId'),
                self.exists('identity.tenantId')
            ]).get_output_in_json()['identity']

src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py:4214: 
 
 
                                      
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
src/azure-cli-testsdk/azure/cli/testsdk/base.py:315: in in_process_execute
    raise ex.exception
env/lib/python3.12/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:677: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:820: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:789: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/aaz/command.py:154: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/resource/aaz/latest/policy/assignment/create.py:50: in handler
    self.execute_operations()
src/azure-cli/azure/cli/command_modules/resource/policy.py:363: in execute_operations
    self.post_operations()
src/azure-cli/azure/cli/command_modules/resource/policy.py:366: in post_operations
    Common.CreateRoleAssignment(self.ctx, self.cli_ctx, self.ctx.vars.instance)
src/azure-cli/azure/cli/command_modules/resource/policy.py:112: in CreateRoleAssignment
    assign_identity(
src/azure-cli-core/azure/cli/core/commands/arm.py:768: in assign_identity
    create_role_assignment(cli_ctx, principal_id, identity_role, identity_scope)
src/azure-cli-core/azure/cli/core/commands/arm.py:790: in create_role_assignment
    assignments_client.create(scope=identity_scope, role_assignment_name=assignment_name,
env/lib/python3.12/site-packages/azure/core/tracing/decorator.py:119: in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/authorization/operations/operations.py:10004: in create
    content = json.dumps(parameters, cls=SdkJSONEncoder, exclude_readonly=True)  # type: ignore
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/json/init.py:238: in dumps
    **kw).encode(obj)
          ^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/json/encoder.py:200: in encode
    chunks = self.iterencode(o, one_shot=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/json/encoder.py:258: in iterencode
    return iterencode(o, 0)
           ^^^^^^^^^^^^^^^^^
env/lib/python3.12/site-packages/azure/mgmt/authorization/utils/model_base.py:166: in default
    return super(SdkJSONEncoder, self).default(o)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                       _ 

self = <azure.mgmt.authorization._utils.model_base.SdkJSONEncoder object at 0x7fdfb77e5250>
o = 'c3514717-7e7c-40ad-b43a-238d4a4b976c'

    def default(self, o):
        """Implement this method in a subclass such that it returns
        a serializable object for o, or calls the base implementation
        (to raise a TypeError).
    
        For example, to support arbitrary iterators, you could
        implement default like this::
    
            def default(self, o):
                try:
                    iterable = iter(o)
                except TypeError:
                    pass
                else:
                    return list(iterable)
                # Let the base class default method raise the TypeError
                return super().default(o)
    
        """
>       raise TypeError(f'Object of type {o.class.name} '
                        f'is not JSON serializable')
E       TypeError: Object of type AAZSimpleValue is not JSON serializable

/opt/hostedtoolcache/Python/3.12.12/x64/lib/python3.12/json/encoder.py:180: TypeError
azure/cli/command_modules/resource/tests/latest/test_resource.py:4146
❌3.14
Type Test Case Error Message Line
Failed test_resource_policy_identity self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f47ce626f50>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f47d3890550>
command = 'policy assignment create --policy 06a78e20-9358-41c9-923c-fb736d382a4d -n azurecli-test-policy-assignment000002 -g cl...-scope /subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_policy_identity000001 --role Reader'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.14/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:153: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
                                        

ex = TypeError('Object of type AAZSimpleValue is not JSON serializable')
args = (), kwargs = {}

    def handle_main_exception(ex, *args, **kwargs):  # pylint: disable=unused-argument
        if isinstance(ex, CannotOverwriteExistingCassetteException):
            # This exception usually caused by a no match HTTP request. This is a product error
            # that is caused by change of SDK invocation.
            raise ex
    
>       raise CliExecutionError(ex)
E       azure.cli.testsdk.exceptions.CliExecutionError: The CLI throws exception TypeError during execution and fails the command.

src/azure-cli-testsdk/azure/cli/testsdk/patches.py:35: CliExecutionError

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.resource.tests.latest.test_resource.PolicyScenarioTest testMethod=test_resource_policy_identity>
resource_group = 'cli_test_policy_identity000001'
resource_group_location = 'westus'

    @ResourceGroupPreparer(name_prefix='cli_test_policy_identity')
    @AllowLargeResponse(8192)
    def test_resource_policy_identity(self, resource_group, resource_group_location):
        self.kwargs.update({
            'pan': self.create_random_name('azurecli-test-policy-assignment', 40),
            'bip': '06a78e20-9358-41c9-923c-fb736d382a4d',
            'sub': self.get_subscription_id(),
            'location': resource_group_location,
            'em': 'DoNotEnforce'
        })
    
        with self.assertRaises(InvalidArgumentValueError):
            self.cmd('policy assignment create --policy 'test/error_policy' -n {pan} -g {rg} --location {location} --assign-identity --enforcement-mode {em}')
    
        # create a policy assignment with managed identity using a built in policy definition
        assignmentIdentity = self.cmd('policy assignment create --policy {bip} -n {pan} -g {rg} --location {location} --assign-identity --enforcement-mode {em}', checks=[
            self.check('name', '{pan}'),
            self.check('location', '{location}'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ]).get_output_in_json()['identity']
    
        # ensure managed identity details are retrievable directly through 'policy assignment identity' commands
        self.cmd('policy assignment identity show -n {pan} -g {rg}', checks=[
            self.check('type', assignmentIdentity['type']),
            self.check('principalId', assignmentIdentity['principalId']),
            self.check('tenantId', assignmentIdentity['tenantId'])
        ])
    
        # ensure the managed identity is not touched during update
        self.cmd('policy assignment update -n {pan} -g {rg} --description "New description"', checks=[
            self.check('description', 'New description'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ])
    
        # remove the managed identity and ensure it is removed when retrieving the policy assignment
        self.cmd('policy assignment identity remove -n {pan} -g {rg}', checks=[
            self.check('type', 'None')
        ])
        self.cmd('policy assignment show -n {pan} -g {rg}', checks=[
            self.check('name', '{pan}'),
            self.check('identity.type', 'None')
        ])
    
        # add an identity using 'identity assign'
        self.cmd('policy assignment identity assign -n {pan} -g {rg}', checks=[
            self.check('type', 'SystemAssigned'),
            self.exists('principalId'),
            self.exists('tenantId')
        ])
        self.cmd('policy assignment show -n {pan} -g {rg}', checks=[
            self.check('name', '{pan}'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ])
    
        self.cmd('policy assignment identity remove -n {pan} -g {rg}', checks=[
            self.check('type', 'None')
        ])
    
        # create a role assignment for the identity using --assign-identity
        self.kwargs.update({
            'idScope': '/subscriptions/{sub}/resourceGroups/{rg}'.format(**self.kwargs),
            'idRole': 'Reader'
        })
        with mock.patch('azure.cli.core.commands.arm.gen_guid', side_effect=self.create_guid):
>           assignmentIdentity = self.cmd('policy assignment create --policy {bip} -n {pan} -g {rg} --location {location} --assign-identity --identity-scope {idScope} --role {idRole}', checks=[
                self.check('name', '{pan}'),
                self.check('location', '{location}'),
                self.check('identity.type', 'SystemAssigned'),
                self.exists('identity.principalId'),
                self.exists('identity.tenantId')
            ]).get_output_in_json()['identity']

src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py:4114: 
 
 
                                      
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
src/azure-cli-testsdk/azure/cli/testsdk/base.py:315: in in_process_execute
    raise ex.exception
env/lib/python3.14/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:677: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:820: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:789: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/aaz/command.py:154: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/resource/aaz/latest/policy/assignment/create.py:50: in handler
    self.execute_operations()
src/azure-cli/azure/cli/command_modules/resource/policy.py:363: in execute_operations
    self.post_operations()
src/azure-cli/azure/cli/command_modules/resource/policy.py:366: in post_operations
    Common.CreateRoleAssignment(self.ctx, self.cli_ctx, self.ctx.vars.instance)
src/azure-cli/azure/cli/command_modules/resource/policy.py:112: in CreateRoleAssignment
    assign_identity(
src/azure-cli-core/azure/cli/core/commands/arm.py:768: in assign_identity
    create_role_assignment(cli_ctx, principal_id, identity_role, identity_scope)
src/azure-cli-core/azure/cli/core/commands/arm.py:790: in create_role_assignment
    assignments_client.create(scope=identity_scope, role_assignment_name=assignment_name,
env/lib/python3.14/site-packages/azure/core/tracing/decorator.py:119: in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/mgmt/authorization/operations/operations.py:10004: in create
    content = json.dumps(parameters, cls=SdkJSONEncoder, exclude_readonly=True)  # type: ignore
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.2/x64/lib/python3.14/json/init.py:242: in dumps
    **kw).encode(obj)
          ^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.2/x64/lib/python3.14/json/encoder.py:202: in encode
    chunks = self.iterencode(o, one_shot=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.2/x64/lib/python3.14/json/encoder.py:263: in iterencode
    return iterencode(o, 0)
           ^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/mgmt/authorization/utils/model_base.py:166: in default
    return super(SdkJSONEncoder, self).default(o)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                       _ 

self = <azure.mgmt.authorization._utils.model_base.SdkJSONEncoder object at 0x7f47ce3470e0>
o = '5ce0ff0d-b4af-49f8-8f81-eb5e8cc665d2'

    def default(self, o):
        """Implement this method in a subclass such that it returns
        a serializable object for o, or calls the base implementation
        (to raise a TypeError).
    
        For example, to support arbitrary iterators, you could
        implement default like this::
    
            def default(self, o):
                try:
                    iterable = iter(o)
                except TypeError:
                    pass
                else:
                    return list(iterable)
                # Let the base class default method raise the TypeError
                return super().default(o)
    
        """
>       raise TypeError(f'Object of type {o.class.name} '
                        f'is not JSON serializable')
E       TypeError: Object of type AAZSimpleValue is not JSON serializable
E       when serializing dict item 'principalId'
E       when serializing azure.mgmt.authorization.models._models.RoleAssignmentProperties object
E       when serializing dict item 'properties'
E       when serializing azure.mgmt.authorization.models._models.RoleAssignmentCreateParameters object

/opt/hostedtoolcache/Python/3.14.2/x64/lib/python3.14/json/encoder.py:182: TypeError
azure/cli/command_modules/resource/tests/latest/test_resource.py:4043
Failed test_resource_policy_identity_systemassigned self = <azure.cli.testsdk.base.ExecutionResult object at 0x7f47ce796550>
cli_ctx = <azure.cli.core.mock.DummyCli object at 0x7f47d3891090>
command = 'policy assignment create --policy 06a78e20-9358-41c9-923c-fb736d382a4d -n azurecli-test-policy-assignment000002 -g cl...ptions/00000000-0000-0000-0000-000000000000/resourceGroups/cli_test_policy_identity_systemassigned000001 --role Reader'
expect_failure = False

    def in_process_execute(self, cli_ctx, command, expect_failure=False):
        from io import StringIO
        from vcr.errors import CannotOverwriteExistingCassetteException
    
        if command.startswith('az '):
            command = command[3:]
    
        stdout_buf = StringIO()
        logging_buf = StringIO()
        try:
            # issue: stderr cannot be redirect in this form, as a result some failure information
            # is lost when command fails.
>           self.exit_code = cli_ctx.invoke(shlex.split(command), out_file=stdout_buf) or 0
                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

src/azure-cli-testsdk/azure/cli/testsdk/base.py:303: 
                                        
env/lib/python3.14/site-packages/knack/cli.py:245: in invoke
    exit_code = self.exception_handler(ex)
                ^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/init.py:153: in exception_handler
    return handle_exception(ex)
           ^^^^^^^^^^^^^^^^^^^^
                                        

ex = TypeError('Object of type AAZSimpleValue is not JSON serializable')
args = (), kwargs = {}

    def handle_main_exception(ex, *args, **kwargs):  # pylint: disable=unused-argument
        if isinstance(ex, CannotOverwriteExistingCassetteException):
            # This exception usually caused by a no match HTTP request. This is a product error
            # that is caused by change of SDK invocation.
            raise ex
    
>       raise CliExecutionError(ex)
E       azure.cli.testsdk.exceptions.CliExecutionError: The CLI throws exception TypeError during execution and fails the command.

src/azure-cli-testsdk/azure/cli/testsdk/patches.py:35: CliExecutionError

During handling of the above exception, another exception occurred:

self = <azure.cli.command_modules.resource.tests.latest.test_resource.PolicyScenarioTest testMethod=test_resource_policy_identity_systemassigned>
resource_group = 'cli_test_policy_identity_systemassigned000001'
resource_group_location = 'westus'

    @ResourceGroupPreparer(name_prefix='cli_test_policy_identity_systemassigned')
    @AllowLargeResponse(8192)
    def test_resource_policy_identity_systemassigned(self, resource_group, resource_group_location):
        self.kwargs.update({
            'pan': self.create_random_name('azurecli-test-policy-assignment', 40),
            'bip': '06a78e20-9358-41c9-923c-fb736d382a4d',
            'sub': self.get_subscription_id(),
            'location': resource_group_location,
            'em': 'DoNotEnforce'
        })
    
        # create a policy assignment with managed identity using a built in policy definition
        assignmentIdentity = self.cmd('policy assignment create --policy {bip} -n {pan} -g {rg} --location {location} --mi-system-assigned --enforcement-mode {em}', checks=[
            self.check('name', '{pan}'),
            self.check('location', '{location}'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ]).get_output_in_json()['identity']
    
        # ensure managed identity details are retrievable directly through 'policy assignment identity' commands
        self.cmd('policy assignment identity show -n {pan} -g {rg}', checks=[
            self.check('type', assignmentIdentity['type']),
            self.check('principalId', assignmentIdentity['principalId']),
            self.check('tenantId', assignmentIdentity['tenantId'])
        ])
    
        # ensure the managed identity is not touched during update
        self.cmd('policy assignment update -n {pan} -g {rg} --description "New description"', checks=[
            self.check('description', 'New description'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ])
    
        # remove the managed identity and ensure it is removed when retrieving the policy assignment
        self.cmd('policy assignment identity remove -n {pan} -g {rg}', checks=[
            self.check('type', 'None')
        ])
        self.cmd('policy assignment show -n {pan} -g {rg}', checks=[
            self.check('name', '{pan}'),
            self.check('identity.type', 'None')
        ])
    
        # add an identity using 'identity assign'
        self.cmd('policy assignment identity assign --system-assigned -n {pan} -g {rg}', checks=[
            self.check('type', 'SystemAssigned'),
            self.exists('principalId'),
            self.exists('tenantId')
        ])
        self.cmd('policy assignment show -n {pan} -g {rg}', checks=[
            self.check('name', '{pan}'),
            self.check('identity.type', 'SystemAssigned'),
            self.exists('identity.principalId'),
            self.exists('identity.tenantId')
        ])
    
        self.cmd('policy assignment identity remove -n {pan} -g {rg}', checks=[
            self.check('type', 'None')
        ])
    
        # create a role assignment for the identity using --mi-system-assigned
        self.kwargs.update({
            'idScope': '/subscriptions/{sub}/resourceGroups/{rg}'.format(**self.kwargs),
            'idRole': 'Reader'
        })
        with mock.patch('azure.cli.core.commands.arm.gen_guid', side_effect=self.create_guid):
>           assignmentIdentity = self.cmd('policy assignment create --policy {bip} -n {pan} -g {rg} --location {location} --mi-system-assigned --identity-scope {idScope} --role {idRole}', checks=[
                self.check('name', '{pan}'),
                self.check('location', '{location}'),
                self.check('identity.type', 'SystemAssigned'),
                self.exists('identity.principalId'),
                self.exists('identity.tenantId')
            ]).get_output_in_json()['identity']

src/azure-cli/azure/cli/command_modules/resource/tests/latest/test_resource.py:4214: 
 
 
                                      
src/azure-cli-testsdk/azure/cli/testsdk/base.py:177: in cmd
    return execute(self.cli_ctx, command, expect_failure=expect_failure).assert_with_checks(checks)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-testsdk/azure/cli/testsdk/base.py:252: in init
    self.in_process_execute(cli_ctx, command, expect_failure=expect_failure)
src/azure-cli-testsdk/azure/cli/testsdk/base.py:315: in in_process_execute
    raise ex.exception
env/lib/python3.14/site-packages/knack/cli.py:233: in invoke
    cmd_result = self.invocation.execute(args)
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:677: in execute
    raise ex
src/azure-cli-core/azure/cli/core/commands/init.py:820: in run_jobs_serially
    results.append(self.run_job(expanded_arg, cmd_copy))
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/commands/init.py:789: in run_job
    result = cmd_copy(params)
             ^^^^^^^^^^^^^^^^
src/azure-cli-core/azure/cli/core/aaz/command.py:154: in call
    return self.handler(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/azure-cli/azure/cli/command_modules/resource/aaz/latest/policy/assignment/create.py:50: in handler
    self.execute_operations()
src/azure-cli/azure/cli/command_modules/resource/policy.py:363: in execute_operations
    self.post_operations()
src/azure-cli/azure/cli/command_modules/resource/policy.py:366: in post_operations
    Common.CreateRoleAssignment(self.ctx, self.cli_ctx, self.ctx.vars.instance)
src/azure-cli/azure/cli/command_modules/resource/policy.py:112: in CreateRoleAssignment
    assign_identity(
src/azure-cli-core/azure/cli/core/commands/arm.py:768: in assign_identity
    create_role_assignment(cli_ctx, principal_id, identity_role, identity_scope)
src/azure-cli-core/azure/cli/core/commands/arm.py:790: in create_role_assignment
    assignments_client.create(scope=identity_scope, role_assignment_name=assignment_name,
env/lib/python3.14/site-packages/azure/core/tracing/decorator.py:119: in wrapper_use_tracer
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/mgmt/authorization/operations/operations.py:10004: in create
    content = json.dumps(parameters, cls=SdkJSONEncoder, exclude_readonly=True)  # type: ignore
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.2/x64/lib/python3.14/json/init.py:242: in dumps
    **kw).encode(obj)
          ^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.2/x64/lib/python3.14/json/encoder.py:202: in encode
    chunks = self.iterencode(o, one_shot=True)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
/opt/hostedtoolcache/Python/3.14.2/x64/lib/python3.14/json/encoder.py:263: in iterencode
    return iterencode(o, 0)
           ^^^^^^^^^^^^^^^^^
env/lib/python3.14/site-packages/azure/mgmt/authorization/utils/model_base.py:166: in default
    return super(SdkJSONEncoder, self).default(o)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
                       _ 

self = <azure.mgmt.authorization._utils.model_base.SdkJSONEncoder object at 0x7f47ce45cc20>
o = 'c3514717-7e7c-40ad-b43a-238d4a4b976c'

    def default(self, o):
        """Implement this method in a subclass such that it returns
        a serializable object for o, or calls the base implementation
        (to raise a TypeError).
    
        For example, to support arbitrary iterators, you could
        implement default like this::
    
            def default(self, o):
                try:
                    iterable = iter(o)
                except TypeError:
                    pass
                else:
                    return list(iterable)
                # Let the base class default method raise the TypeError
                return super().default(o)
    
        """
>       raise TypeError(f'Object of type {o.class.name} '
                        f'is not JSON serializable')
E       TypeError: Object of type AAZSimpleValue is not JSON serializable
E       when serializing dict item 'principalId'
E       when serializing azure.mgmt.authorization.models._models.RoleAssignmentProperties object
E       when serializing dict item 'properties'
E       when serializing azure.mgmt.authorization.models._models.RoleAssignmentCreateParameters object

/opt/hostedtoolcache/Python/3.14.2/x64/lib/python3.14/json/encoder.py:182: TypeError
azure/cli/command_modules/resource/tests/latest/test_resource.py:4146
️✔️role
️✔️latest
️✔️3.12
️✔️3.14
️✔️search
️✔️latest
️✔️3.12
️✔️3.14
️✔️security
️✔️latest
️✔️3.12
️✔️3.14
️✔️servicebus
️✔️latest
️✔️3.12
️✔️3.14
️✔️serviceconnector
️✔️latest
️✔️3.12
️✔️3.14
️✔️servicefabric
️✔️latest
️✔️3.12
️✔️3.14
️✔️signalr
️✔️latest
️✔️3.12
️✔️3.14
️✔️sql
️✔️latest
️✔️3.12
️✔️3.14
️✔️sqlvm
️✔️latest
️✔️3.12
️✔️3.14
️✔️storage
️✔️latest
️✔️3.12
️✔️3.14
️✔️synapse
️✔️latest
️✔️3.12
️✔️3.14
️✔️telemetry
️✔️latest
️✔️3.12
️✔️3.14
️✔️util
️✔️latest
️✔️3.12
️✔️3.14
️✔️vm
️✔️latest
️✔️3.12
️✔️3.14

@azure-client-tools-bot-prd

azure-client-tools-bot-prd Bot commented Mar 31, 2026

Copy link
Copy Markdown
⚠️AzureCLI-BreakingChangeTest
⚠️role
rule cmd_name rule_message suggest_message
⚠️ 1011 - SubgroupAdd role deny-assignment sub group role deny-assignment added

@yonzhan

yonzhan commented Mar 31, 2026

Copy link
Copy Markdown
Collaborator

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

@github-actions

Copy link
Copy Markdown

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>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds first-class az role deny-assignment CRUD support (focused on PP1 user-assigned deny assignments) to align with existing role assignment workflows, including command registration, parameters, help, and tests.

Changes:

  • Register az role deny-assignment list/show/create/delete commands and add a table transformer for list output.
  • Implement deny-assignment list/show/create/delete custom handlers with PP1 validation.
  • Add help/params, linter exclusions for long options, and introduce a new deny-assignment test file.

Reviewed changes

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

Show a summary per file
File Description
src/azure-cli/azure/cli/command_modules/role/custom.py Adds deny-assignment list/show/create/delete implementations and PP1 input validation.
src/azure-cli/azure/cli/command_modules/role/commands.py Registers new role deny-assignment commands and list table transformer.
src/azure-cli/azure/cli/command_modules/role/_params.py Defines CLI parameters for deny-assignment commands.
src/azure-cli/azure/cli/command_modules/role/_help.py Adds help text and examples for the new/updated deny-assignment commands.
src/azure-cli/azure/cli/command_modules/role/linter_exclusions.yml Excludes option-length lint rules for new long parameter names.
src/azure-cli/azure/cli/command_modules/role/tests/latest/test_deny_assignment.py Adds scenario/live tests covering list/show and PP1 create/delete validation.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +627 to +638
'deny_assignment_name': deny_assignment_name,
'description': description or '',
'permissions': [{
'actions': actions or [],
'not_actions': not_actions or [],
'data_actions': [],
'not_data_actions': []
}],
'scope': scope,
'principals': principals,
'exclude_principals': exclude_principals,
'is_system_protected': False

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

create_deny_assignment builds the request body as a plain dict using snake_case keys (e.g. deny_assignment_name, not_actions, exclude_principals). For mgmt SDK operations, dicts are typically serialized as-is, so the service will receive incorrect field names (it expects camelCase JSON, or a proper SDK model instance). Use the azure-mgmt-authorization model types via get_sdk(..., mod='models') (similar to RoleApiHelper.create_role_assignment) or ensure the payload keys match the service JSON contract exactly.

Suggested change
'deny_assignment_name': deny_assignment_name,
'description': description or '',
'permissions': [{
'actions': actions or [],
'not_actions': not_actions or [],
'data_actions': [],
'not_data_actions': []
}],
'scope': scope,
'principals': principals,
'exclude_principals': exclude_principals,
'is_system_protected': False
'denyAssignmentName': deny_assignment_name,
'description': description or '',
'permissions': [{
'actions': actions or [],
'notActions': not_actions or [],
'dataActions': [],
'notDataActions': []
}],
'scope': scope,
'principals': principals,
'excludePrincipals': exclude_principals,
'isSystemProtected': False

Copilot uses AI. Check for mistakes.
Comment on lines +641 to +642
return deny_client.create(scope=scope, deny_assignment_id=assignment_name,
parameters=deny_assignment_params)

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

This calls authorization_client.deny_assignments.create(...), but the repo currently pins azure-mgmt-authorization==5.0.0b1 (which does not include denyAssignments create/delete per the PR description). Without bumping the SDK dependency (or adding a fallback implementation / friendly error), this command will raise AttributeError at runtime.

Copilot uses AI. Check for mistakes.
Comment on lines +645 to +654
def delete_deny_assignment(cmd, scope=None, deny_assignment_id=None, deny_assignment_name=None):
"""Delete a user-assigned deny assignment."""
authorization_client = _auth_client_factory(cmd.cli_ctx, scope)
deny_client = authorization_client.deny_assignments

if deny_assignment_id:
return deny_client.delete_by_id(deny_assignment_id)
if deny_assignment_name and scope:
return deny_client.delete(scope=scope, deny_assignment_id=deny_assignment_name)
raise CLIError('Please provide --id, or both --name and --scope.')

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

Same dependency issue as create: deny_client.delete(...)/delete_by_id(...) will fail at runtime unless the pinned azure-mgmt-authorization version includes these methods. Consider either updating the dependency in this PR or detecting missing methods and raising a clear CLIError instructing users to upgrade.

Copilot uses AI. Check for mistakes.
Comment on lines +397 to +398
c.argument('deny_assignment_name', options_list=['--name', '-n'],
help='The display name of the deny assignment.')

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

deny_assignment_name is defined at the role deny-assignment group level, which makes --name/-n show up for subcommands like list even though list_deny_assignments doesn't accept that parameter. If a user supplies --name on list, the handler will receive an unexpected kwarg and fail. Recommend removing deny_assignment_name from the group context and defining --name only on show/create/delete where it is supported.

Suggested change
c.argument('deny_assignment_name', options_list=['--name', '-n'],
help='The display name of the deny assignment.')

Copilot uses AI. Check for mistakes.
c.argument('exclude_principal_ids', nargs='+', options_list=['--exclude-principal-ids'],
help='Space-separated list of principal object IDs to exclude from the deny. '
'At least one is required for user-assigned deny assignments.')
c.argument('exclude_principal_types', nargs='+', options_list=['--exclude-principal-types'],

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

--exclude-principal-types is documented as having accepted values, but the argument doesn't enforce them. To keep validation consistent with role assignment create --assignee-principal-type, use arg_type=get_enum_type([...]) (or an Enum) so invalid values are caught client-side with a clear error.

Suggested change
c.argument('exclude_principal_types', nargs='+', options_list=['--exclude-principal-types'],
c.argument('exclude_principal_types', nargs='+', options_list=['--exclude-principal-types'],
arg_type=get_enum_type(['User', 'Group', 'ServicePrincipal']),

Copilot uses AI. Check for mistakes.
Comment on lines +15 to +35
class DenyAssignmentListTest(ScenarioTest):
"""Tests for az role deny-assignment list — works on any subscription."""

def test_deny_assignment_list(self):
"""List deny assignments at the subscription scope."""
result = self.cmd('role deny-assignment list').get_output_in_json()
# Result should be a list (may be empty if no deny assignments exist)
self.assertIsInstance(result, list)

def test_deny_assignment_list_with_scope(self):
"""List deny assignments at a specific scope."""
self.cmd('role deny-assignment list --scope /subscriptions/{sub}',
checks=[self.check('type(@)', 'array')])

def test_deny_assignment_list_with_filter(self):
"""List deny assignments with OData filter."""
result = self.cmd(
'role deny-assignment list --filter "atScope()"'
).get_output_in_json()
self.assertIsInstance(result, list)

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

This file adds ScenarioTest cases for role deny-assignment list that will require a new VCR recording to pass in playback mode, but no corresponding recording YAML is added under tests/latest/recordings. Either add recordings for these scenario tests or convert them to mock-based tests (or LiveScenarioTest if they must be live-only) so CI doesn't fail.

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +61
self.kwargs.update({
'scope': '/subscriptions/{sub}',
'name': 'CLI Test Deny Assignment',
'action': 'Microsoft.Authorization/roleAssignments/write',
# Use a well-known object ID for exclusion (replace with a real SP in your test env)
'exclude_id': self.create_guid()

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

exclude_id is set to self.create_guid(), which is a random GUID and is unlikely to correspond to a real principal in the tenant. If the denyAssignment API validates excluded principals, this live test will fail reliably. Prefer creating a real principal in the test setup (or using the signed-in user/service principal object id) and passing its object ID here.

Suggested change
self.kwargs.update({
'scope': '/subscriptions/{sub}',
'name': 'CLI Test Deny Assignment',
'action': 'Microsoft.Authorization/roleAssignments/write',
# Use a well-known object ID for exclusion (replace with a real SP in your test env)
'exclude_id': self.create_guid()
signed_in_user = self.cmd('ad signed-in-user show').get_output_in_json()
exclude_id = signed_in_user['id']
self.kwargs.update({
'scope': '/subscriptions/{sub}',
'name': 'CLI Test Deny Assignment',
'action': 'Microsoft.Authorization/roleAssignments/write',
'exclude_id': exclude_id

Copilot uses AI. Check for mistakes.
# These tests require a subscription with the UserAssignedDenyAssignment feature flag enabled.

import unittest
from unittest import mock

Copilot AI Mar 31, 2026

Copy link

Choose a reason for hiding this comment

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

Unused import: from unittest import mock is not used in this test file. Please remove it to keep linting clean.

Suggested change
from unittest import mock

Copilot uses AI. Check for mistakes.
@jruttle

jruttle commented May 7, 2026

Copy link
Copy Markdown
Member Author

Bumped azure-mgmt-authorization from 5.0.0b15.0.0b2 in src/azure-cli/setup.py (commit 20fe3a79).

This picks up the new DenyAssignment management-plane operations (BeginCreateOrUpdate / BeginDelete) that shipped in azure-mgmt-authorization 5.0.0b2 on PyPI today (release request Azure/azure-sdk-for-python#46551, released by @msyyc at 10:30 UTC).

This was the last upstream blocker on this PR — the CLI commands here now have a real published SDK surface to call against. CC for review awareness: prior reviewers / CLI mgmt module owners.

@jruttle

jruttle commented May 7, 2026

Copy link
Copy Markdown
Member Author

Follow-up to commit 20fe3a79 — the setup.py bump alone wasn't enough; the CI errors

`ERROR: Cannot install azure-cli==2.85.0 and azure-mgmt-authorization==5.0.0b1 because these package versions have conflicting dependencies.`
`  The user requested azure-mgmt-authorization==5.0.0b1`
`  azure-cli 2.85.0 depends on azure-mgmt-authorization==5.0.0b2`

…showed the platform lock files (requirements.py3.Linux.txt, Darwin.txt, windows.txt) were still pinning the old beta. Now bumped in three follow-up commits:

CI should now re-run cleanly on the new HEAD.

@isra-fel

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

@jruttle

jruttle commented May 12, 2026

Copy link
Copy Markdown
Member Author

Hi @yonzhan @isra-fel — could one of you /azp run against the new tip when you get a chance? The pipelines last ran on 11 May 07:03 against f498063b72; since then I've pushed three fix commits on top of the previous SDK-contract patch:

Commit Fix
005aa582ab Three more SDK 5.0.0b2 contract breaks (update_role_assignment ValueError, list_role_assignments KeyError, three positional-filter callers in vm/_validators.py, ams/operations/sp.py, containerapp/_utils.py, acs/_roleassignments.py)
a78903e53e One more positional-filter caller in azure-cli-core/azure/cli/core/commands/arm.py::resolve_role_id (the shared utility most modules call)
90642428ce flake8 E302

I ran each of the previously-failing tests locally in playback against azure-mgmt-authorization 5.0.0b2 via azdev and they all pass:

  • test_role_assignment_create_update ✅ (was: ValueError('No value for given attribute'))
  • test_role_assignment_scenario
  • test_role_assignment_create_using_principal_type
  • test_role_assignment_handle_conflicted_assignments
  • test_create_for_rbac_password_with_assignment ✅ (was: KeyError('roleDefinitionId'))
  • test_vm_msi / test_vm_explicit_msi ✅ (was: TypeError)
  • test_vmss_msi / test_vmss_explicit_msi
  • test_identity_hub ✅ (was: TypeError — needed the arm.py fix in a78903e53e)
  • Full role test sweep: 17 passed, 2 LiveOnly skipped
  • Role unit tests: 14 passed
  • azdev style --pep8: PASSED

One pre-existing test, test_ams_sp_create_reset, still fails locally with a VCR cassette mismatch (CannotOverwriteExistingCassetteException, "Matchers failed: [empty]" = cassette exhausted). The AMS cassette was last updated in the 2.85.0 release (692b407c37) and was not re-recorded when the SDK was bumped to 5.0.0b1 in #31859 — the new SDK makes more identical requests than the cassette has responses for. This is pre-existing on dev and outside the scope of this PR; happy to file a separate issue if helpful.

Thanks!

@jruttle

jruttle commented Jun 16, 2026

Copy link
Copy Markdown
Member Author

Hi team — friendly bump on this PR. It's been waiting 35 days since the last fix commits were pushed (May 12) and all GitHub Actions checks pass (linter, style, CLA).

Could someone please run /azp run\ against the current tip (\90642428ce)? I don't have permissions to trigger it myself.

The three fix commits on May 12 resolved all the \�zure-mgmt-authorization 5.0.0b2\ compatibility issues — all 17 role tests pass locally in playback. Happy to answer any questions about the implementation.

cc @isra-fel @bebound @jiasli @notyashhh @xuming-ms @teresaritorto

@teresaritorto

Copy link
Copy Markdown
Contributor

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

Jonathan Ruttle and others added 13 commits June 18, 2026 14:33
Update create command to support two modes:
- Everyone mode (default): denies all principals, requires exclude-principal-ids
- Per-principal mode: denies a specific User or ServicePrincipal via --principal-id/--principal-type

API changes from DA PR msazure/One#15293894:
- 3P UADA can now target specific User and ServicePrincipal principals
- Group type principals are explicitly disallowed
- Single-principal-per-UADA constraint enforced

Changes:
- custom.py: Add principal_id/principal_type params, dual-mode logic, Group rejection
- _params.py: Add --principal-id and --principal-type (enum) arguments
- _help.py: Update long-summary and examples for both modes
- tests: Add per-principal CRUD, Group rejection, missing-param validation tests

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Now that azure-mgmt-authorization 5.0.0b2 has been published to PyPI
(2026-05-07), this picks up the new DenyAssignment management plane
operations (BeginCreateOrUpdate / BeginDelete) added in PR #46223.

This unblocks the deny-assignment CLI commands in this PR from
running against the new SDK surface.
Follow-up to commit 20fe3a7 which only bumped setup.py.
The Linux/Darwin/Windows requirements lock files also pinned 5.0.0b1
and caused azdev-linter / azdev-style CI to fail with:

  ERROR: Cannot install azure-cli==2.85.0 and azure-mgmt-authorization==5.0.0b1
  because these package versions have conflicting dependencies.

This commit aligns all three platform lock files with setup.py at 5.0.0b2.
…ract changes

The new TypeSpec-generated 5.0.0b2 SDK introduced breaking changes that
block the Full Test pipeline. Changes:

* role/custom.py _resolve_role_id: pass `filter` as a keyword argument to
  RoleDefinitionsOperations.list (its signature is now
  `list(scope, *, filter=None)`). This single line was the root cause for
  the wide blast radius across vm/iot/aro/ams/acr/resource modules and the
  role module's own RoleAssignmentScenarioTest cases - all of them resolve
  roles by name and therefore go through this function.

* role/custom.py update_role_assignment: replace
  `RoleAssignment.from_dict(d)` with `RoleAssignment(d)`. The new Model
  base class accepts a JSON mapping directly and no longer exposes
  from_dict.

* role/custom.py create_deny_assignment: switch from passing a snake_case
  dict to constructing SDK model objects (DenyAssignment,
  DenyAssignmentProperties, DenyAssignmentPermission,
  DenyAssignmentPrincipal). The TypeSpec serializer would have written the
  raw snake_case keys to the wire instead of camelCase. Also rename
  `deny_client.create(...)` to `create_or_update(...)` (the method was
  renamed in the new SDK).

* role/custom.py delete_deny_assignment: the new SDK does not expose
  delete_by_id for deny assignments, so parse the resource ID via a new
  _parse_deny_assignment_id helper (case-insensitive regex that handles
  subscription, resource-group, and management-group scopes) and call
  delete(scope, deny_assignment_id).

* role/custom.py show_deny_assignment / delete_deny_assignment /
  create_deny_assignment: move argument validation ahead of the
  _auth_client_factory(...) call so validation-only error paths don't
  require an authenticated session.

* tests/latest/test_deny_assignment.py: convert DenyAssignmentListTest to
  LiveScenarioTest (these hit the live API and have no recorded cassettes
  in the repo), and replace DenyAssignmentShowTest with a unittest-based
  DenyAssignmentShowValidationTest that calls show_deny_assignment()
  directly and asserts the CLIError - both changes remove the dependency
  on a logged-in session in playback CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Extract _build_deny_assignment_model helper to keep the local count under
the project's max-locals=25 threshold (was 26/25 in azdev-style after the
SDK-model refactor).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Pipeline build 314889 (re-triggered 11 May) still fails because the 8 May patch
did not address every breaking change in the new TypeSpec-generated SDK. This
commit fixes the four remaining classes of issue.

* role/custom.py update_role_assignment: `RoleAssignment(some_dict)` silently
  produces a model with `properties=None` (the new model wraps domain
  attributes under a nested `properties` field, with `__flattened_items`
  exposing them via descriptors only when `properties` is set). The old code
  then read `assignment.scope` -> None and passed scope=None to the SDK URL
  serializer, which raised `ValueError('No value for given attribute')`.
  Read scope/name/principalType/etc. directly from the user-supplied flat
  camelCase dict and send a `{"properties": {...}}` JSON body to .create()
  via its JSON overload - simpler and avoids the new model's flatten/unflatten
  gymnastics. Caused test_role_assignment_create_update.

* role/custom.py list_role_assignments + list_deny_assignments +
  show_deny_assignment: `knack.util.todict` walks `__dict__` and
  therefore returns `{}` for the new MutableMapping-based models, so the
  subsequent `ra['roleDefinitionId']` / `ra['principalId']` lookups
  raised `KeyError`. Added explicit _role_assignment_to_dict and
  _deny_assignment_to_dict adapters that project the model back to the
  legacy flat camelCase shape (with enum -> str coercion) and routed all
  list/show paths through them. Caused
  test_create_for_rbac_password_with_assignment.

* vm/_validators.py, ams/operations/sp.py, containerapp/_utils.py,
  acs/_roleassignments.py: `RoleDefinitionsOperations.list` is now
  `list(scope, *, filter=None)`, so each remaining caller that passed
  filter positionally raised
  `TypeError: list() takes 2 positional arguments but 3 were given`.
  This is the same bug fixed in 2d2c80a for role/custom.py::_resolve_role_id;
  these four call sites were missed. Caused test_vm_msi, test_vm_explicit_msi,
  test_vmss_msi, test_vmss_explicit_msi, test_ams_sp_create_reset, and the
  ACS / Container Apps role-resolution paths.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
While running the previously-failing tests locally to verify 005aa58,
test_identity_hub continued to fail because azure-cli-core itself has its
own resolve_role_id helper at src/azure-cli-core/azure/cli/core/commands/arm.py
that also passed filter positionally to RoleDefinitionsOperations.list.
This is the shared utility many modules call via core.commands.arm.create_role_assignment.

Same one-line fix as the four module-level callers patched in 005aa58:
pass filter as a keyword argument so it works with the new TypeSpec-generated
SDK signature `list(scope, *, filter=None)`.

Local verification (azure-mgmt-authorization 5.0.0b2 installed):
  * test_role_assignment_create_update PASSED (was: ValueError)
  * test_role_assignment_scenario PASSED
  * test_role_assignment_create_using_principal_type PASSED
  * test_role_assignment_handle_conflicted_assignments PASSED
  * test_create_for_rbac_password_with_assignment PASSED (was: KeyError)
  * test_vm_msi PASSED (was: TypeError)
  * test_vm_explicit_msi PASSED
  * test_vmss_msi PASSED
  * test_vmss_explicit_msi PASSED
  * test_identity_hub PASSED (was: TypeError - this commit's fix)
  * Full role test sweep: 17 passed, 2 LiveOnly skipped
  * Role unit tests: 14 passed

test_ams_sp_create_reset still fails with VCR cassette mismatch (the cassette
was recorded against azure-mgmt-authorization 4.x but dev branch bumped to
5.0.0b1 in Azure#31859 without re-recording AMS cassettes; multiple identical
requests now exhaust the single recorded response). This is pre-existing on
dev and outside the scope of this PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The azdev-style GitHub Actions check (run id 25725694563) failed flake8 on
the new `_coerce` function added in 005aa58 because it followed the
section comment block with only one blank line. Adding the second blank line
resolves the two reported E302 errors at line 46.

Verified locally with `azdev style --pep8` -> Flake8: PASSED.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@jruttle jruttle force-pushed the jruttle/add-deny-assignment-commands branch from 9064242 to 07b2efa Compare June 18, 2026 13:34
@jruttle jruttle requested a review from MaddyMicrosoft as a code owner June 18, 2026 13:34
@notyashhh

Copy link
Copy Markdown
Member

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines successfully started running 3 pipeline(s).

@isra-fel isra-fel left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Hi please see the inline comment about aligning the design of assignment and deny-assignment. Also please make sure CI is green.

'Note: read actions (*/read) are not permitted for user-assigned deny assignments.')
c.argument('not_actions', nargs='+',
help='Space-separated list of actions to exclude from the deny.')
c.argument('principal_id', options_list=['--principal-id'],

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants