From 336c6ca00673c96e4694aedcb13b9695e0e86701 Mon Sep 17 00:00:00 2001
From: kai ru <kairu@microsoft.com>
Date: Thu, 23 Jan 2025 11:43:43 +0800
Subject: [PATCH] {core} --set: Minor fix

---
 .../azure/cli/core/commands/arm.py            | 12 +++---
 src/azure-cli-core/azure/cli/core/util.py     | 38 +++++++++++++++++++
 2 files changed, 44 insertions(+), 6 deletions(-)

diff --git a/src/azure-cli-core/azure/cli/core/commands/arm.py b/src/azure-cli-core/azure/cli/core/commands/arm.py
index 15d7a4d250..89c90853cb 100644
--- a/src/azure-cli-core/azure/cli/core/commands/arm.py
+++ b/src/azure-cli-core/azure/cli/core/commands/arm.py
@@ -15,7 +15,7 @@ from azure.cli.core.commands import LongRunningOperation
 from azure.cli.core.commands.client_factory import get_mgmt_service_client
 from azure.cli.core.commands.events import EVENT_INVOKER_PRE_LOAD_ARGUMENTS
 from azure.cli.core.commands.validators import IterateValue
-from azure.cli.core.util import shell_safe_json_parse, get_command_type_kwarg
+from azure.cli.core.util import shell_safe_json_parse, get_command_type_kwarg, getprop
 from azure.cli.core.profiles import ResourceType, get_sdk
 
 from knack.arguments import CLICommandArgument, ignore_type
@@ -597,7 +597,7 @@ def remove_properties(instance, argument_values):
 def throw_and_show_options(instance, part, path):
     from msrest.serialization import Model
     options = instance.__dict__ if hasattr(instance, '__dict__') else instance
-    if isinstance(instance, Model) and isinstance(getattr(instance, 'additional_properties', None), dict):
+    if isinstance(instance, Model) and isinstance(getprop(instance, 'additional_properties', None), dict):
         options.update(options.pop('additional_properties'))
     parent = '.'.join(path[:-1]).replace('.[', '[')
     error_message = "Couldn't find '{}' in '{}'.".format(part, parent)
@@ -670,7 +670,7 @@ def _update_instance(instance, part, path):  # pylint: disable=too-many-return-s
                     matches.append(x)
                 elif not isinstance(x, dict):
                     snake_key = make_snake_case(key)
-                    if hasattr(x, snake_key) and getattr(x, snake_key, None) == value:
+                    if hasattr(x, snake_key) and getprop(x, snake_key, None) == value:
                         matches.append(x)
 
             if len(matches) == 1:
@@ -678,7 +678,7 @@ def _update_instance(instance, part, path):  # pylint: disable=too-many-return-s
             if len(matches) > 1:
                 raise CLIError("non-unique key '{}' found multiple matches on {}. Key must be unique."
                                .format(key, path[-2]))
-            if key in getattr(instance, 'additional_properties', {}):
+            if key in getprop(instance, 'additional_properties', {}):
                 instance.enable_additional_properties_sending()
                 return instance.additional_properties[key]
             raise CLIError("item with value '{}' doesn\'t exist for key '{}' on {}".format(value, key, path[-2]))
@@ -694,8 +694,8 @@ def _update_instance(instance, part, path):  # pylint: disable=too-many-return-s
             return instance[part]
 
         if hasattr(instance, make_snake_case(part)):
-            return getattr(instance, make_snake_case(part), None)
-        if part in getattr(instance, 'additional_properties', {}):
+            return getprop(instance, make_snake_case(part), None)
+        if part in getprop(instance, 'additional_properties', {}):
             instance.enable_additional_properties_sending()
             return instance.additional_properties[part]
         raise AttributeError()
diff --git a/src/azure-cli-core/azure/cli/core/util.py b/src/azure-cli-core/azure/cli/core/util.py
index c025761d66..aea924e38c 100644
--- a/src/azure-cli-core/azure/cli/core/util.py
+++ b/src/azure-cli-core/azure/cli/core/util.py
@@ -1305,3 +1305,41 @@ def rmtree_with_retry(path):
             else:
                 logger.warning("Failed to delete '%s': %s. You may try to delete it manually.", path, err)
                 break
+
+
+def get_secret_store(cli_ctx, name):
+    """Create a process-concurrency-safe azure.cli.core.auth.persistence.SecretStore instance that can be used to
+    save secret data.
+    """
+    from azure.cli.core._environment import get_config_dir
+    from azure.cli.core.auth.persistence import load_secret_store
+    # Save to CLI's config dir, by default ~/.azure
+    location = os.path.join(get_config_dir(), name)
+    # We honor the system type (Windows, Linux, or MacOS) and global config
+    encrypt = should_encrypt_token_cache(cli_ctx)
+    return load_secret_store(location, encrypt)
+
+
+def should_encrypt_token_cache(cli_ctx):
+    # Only enable encryption for Windows (for now).
+    fallback = sys.platform.startswith('win32')
+
+    # EXPERIMENTAL: Use core.encrypt_token_cache=False to turn off token cache encryption.
+    # encrypt_token_cache affects both MSAL token cache and service principal entries.
+    encrypt = cli_ctx.config.getboolean('core', 'encrypt_token_cache', fallback=fallback)
+
+    return encrypt
+
+
+def getprop(o, name, *default):
+    """ This function is used to get the property of the object.
+    It will raise an error if the property is a private property or a method.
+    """
+    if name.startswith('_'):
+        # avoid to access the private properties or methods
+        raise KeyError(name)
+    v = getattr(o, name, *default)
+    if callable(v):
+        # avoid to access the methods
+        raise KeyError(name)
+    return v
-- 
2.49.0

