Repository: cloud-custodian/cloud-custodian

Issue:
azure.identity._credentials.azure_cli._run_command now has a different signature
https://github.com/cloud-custodian/cloud-custodian/blob/f7cc5a287cd4e0281508a5d468f507c0116efd42/tools/c7n_azure/c7n_azure/session.py#L93

The method signature now has, as a second parameter, `timeout`. This is causing issues when trying to use Azure CLI login, which happens automatically when using AzlueCLI@2 task in Azure DevOps, for example.

Also, for additional context, here is the PR into azure-sdk-for-python that introduced that change: https://github.com/Azure/azure-sdk-for-python/pull/28290


Discussion:

Resolving patch:
diff --git a/tools/c7n_azure/c7n_azure/session.py b/tools/c7n_azure/c7n_azure/session.py
--- a/tools/c7n_azure/c7n_azure/session.py
+++ b/tools/c7n_azure/c7n_azure/session.py
@@ -90,7 +90,7 @@ def __init__(self, cloud_endpoints, authorization_file=None, subscription_id_ove
         elif self._auth_params.get('enable_cli_auth'):
             auth_name = 'Azure CLI'
             self._credential = AzureCliCredential()
-            account_info = _run_command('az account show --output json')
+            account_info = _run_command('az account show --output json', timeout=10)
             account_json = json.loads(account_info)
             self._auth_params['subscription_id'] = account_json['id']
             self._auth_params['tenant_id'] = account_json['tenantId']


Test patch:
diff --git a/tools/c7n_azure/tests_azure/test_session.py b/tools/c7n_azure/tests_azure/test_session.py
--- a/tools/c7n_azure/tests_azure/test_session.py
+++ b/tools/c7n_azure/tests_azure/test_session.py
@@ -3,11 +3,13 @@
 import json
 import os
 import re
+from inspect import signature
 
 import pytest
 from adal import AdalError
 from azure.core.credentials import AccessToken
 from azure.identity import (ClientSecretCredential, ManagedIdentityCredential)
+from azure.identity._credentials import azure_cli
 from c7n_azure import constants
 from c7n_azure.session import Session
 from mock import patch
@@ -87,6 +89,29 @@ def test_initialize_session_cli(self, mock_run):
             self.assertEqual(s.get_subscription_id(), DEFAULT_SUBSCRIPTION_ID)
             self.assertEqual(s.get_tenant_id(), DEFAULT_TENANT_ID)
 
+    def test_run_command_signature(self):
+        """Catch signature changes in the internal method we use for CLI authentication
+
+        We use _run_command() to fetch default subscription information. This information
+        was previously accessible via azure-common but has been deprecated in favor
+        of azure-identity:
+
+        https://github.com/Azure/azure-sdk-for-python/blob/main/sdk/identity/azure-identity/migration_guide.md
+
+        It's not clear how to reliably get the CLI's default subscription purely from
+        azure-identity (avoiding an explicit azure-cli dependency). Azure CLI docs suggest
+        that while we can _usually_ pull default subscription info out of ~/.azure/azureProfile,
+        it might be elsewhere:
+
+        https://github.com/Azure/azure-cli/blob/813da51a0a6ac2d427e496f1dffc01c96af24d78/src/azure-cli-core/azure/cli/core/_profile.py#L20-L24
+
+        So continuing to rely on _run_command() may be more reliable, as long as we
+        catch signature changes to avoid accidental breakage.
+        """
+        expected_parameters = {"command", "timeout"}
+        actual_parameters = set(signature(azure_cli._run_command).parameters.keys())
+        self.assertSetEqual(expected_parameters, actual_parameters)
+
     @patch('azure.identity.ClientSecretCredential.get_token')
     @patch('c7n_azure.session.log.error')
     def test_initialize_session_authentication_error(self, mock_log, mock_cred):