Skip to content

Commit ba6065c

Browse files
pratiksanglikarPratik Sanglikar
andauthored
{App Config} Fix #12668860, #12668922: Fix validations while importing kvset (#20491)
* Fix validations while importing kvset * Fix styling errors * Fix sample --label is not supported * Address feedback comments * Resolve feedback comments * fix warning message * Resolve feedback comments * Fix styling errors * Use dict.get with default Co-authored-by: Pratik Sanglikar <prsangli@microsoft.com>
1 parent df7aaf1 commit ba6065c

File tree

2 files changed

+54
-20
lines changed

2 files changed

+54
-20
lines changed

src/azure-cli/azure/cli/command_modules/appconfig/_help.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@
148148
- name: Import all keys to another App Configuration using your 'az login' credentials.
149149
text: az appconfig kv import -s appconfig --endpoint https://myappconfiguration.azconfig.io --auth-mode login --src-endpoint https://anotherappconfiguration.azconfig.io --src-auth-mode login --src-key * --src-label * --preserve-labels
150150
- name: Import all keys and feature flags from a file using the appconfig/kvset format.
151-
text: az appconfig kv import -n MyAppConfiguration --label test -s file --path D:/abc.json --format json --profile appconfig/kvset
151+
text: az appconfig kv import -n MyAppConfiguration -s file --path D:/abc.json --format json --profile appconfig/kvset
152152
"""
153153

154154
helps['appconfig kv list'] = """

src/azure-cli/azure/cli/command_modules/appconfig/_kv_helpers.py

Lines changed: 53 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# Licensed under the MIT License. See License.txt in the project root for license information.
44
# --------------------------------------------------------------------------------------------
55

6-
# pylint: disable=line-too-long,too-many-nested-blocks,too-many-lines
6+
# pylint: disable=line-too-long,too-many-nested-blocks,too-many-lines,too-many-return-statements
77

88
import io
99
import json
@@ -97,6 +97,9 @@ def __compare_kvs_for_restore(restore_kvs, current_kvs):
9797

9898
def validate_import_key(key):
9999
if key:
100+
if not isinstance(key, str):
101+
logger.warning("Ignoring invalid key '%s'. Key must be a string.", key)
102+
return False
100103
if key == '.' or key == '..' or '%' in key:
101104
logger.warning("Ignoring invalid key '%s'. Key cannot be a '.' or '..', or contain the '%%' character.", key)
102105
return False
@@ -106,7 +109,6 @@ def validate_import_key(key):
106109
else:
107110
logger.warning("Ignoring invalid key ''. Key cannot be empty.")
108111
return False
109-
110112
return True
111113

112114

@@ -380,13 +382,13 @@ def __write_kv_and_features_to_config_store(azconfig_client,
380382

381383

382384
def __is_feature_flag(kv):
383-
if kv and kv.key and kv.content_type:
385+
if kv and kv.key and isinstance(kv.key, str) and kv.content_type and isinstance(kv.content_type, str):
384386
return kv.key.startswith(FeatureFlagConstants.FEATURE_FLAG_PREFIX) and kv.content_type == FeatureFlagConstants.FEATURE_FLAG_CONTENT_TYPE
385387
return False
386388

387389

388390
def __is_key_vault_ref(kv):
389-
return kv and kv.content_type and kv.content_type.lower() == KeyVaultConstants.KEYVAULT_CONTENT_TYPE
391+
return kv and kv.content_type and isinstance(kv.content_type, str) and kv.content_type.lower() == KeyVaultConstants.KEYVAULT_CONTENT_TYPE
390392

391393

392394
def __discard_features_from_retrieved_kv(src_kvs):
@@ -1027,13 +1029,19 @@ def __import_kvset_from_file(client, path, yes):
10271029
if KVSetConstants.KVSETRootElementName not in new_kvset:
10281030
raise FileOperationError("file '{0}' is not in a valid '{1}' format.".format(path, ImportExportProfiles.KVSET))
10291031

1030-
kvset_to_import = [ConfigurationSetting(key=kv['key'],
1031-
label=kv['label'],
1032-
content_type=kv['content_type'],
1033-
value=kv['value'],
1034-
tags=kv['tags'])
1032+
kvset_from_file = [ConfigurationSetting(key=kv.get('key', None),
1033+
label=kv.get('label', None),
1034+
content_type=kv.get('content_type', None),
1035+
value=kv.get('value', None),
1036+
tags=kv.get('tags', None))
10351037
for kv in new_kvset[KVSetConstants.KVSETRootElementName]]
10361038

1039+
kvset_to_import = []
1040+
1041+
for config_setting in kvset_from_file:
1042+
if __validate_import_config_setting(config_setting):
1043+
kvset_to_import.append(config_setting)
1044+
10371045
if not yes:
10381046
existing_kvset = __read_kv_from_config_store(client,
10391047
key=SearchFilterOptions.ANY_KEY,
@@ -1056,16 +1064,6 @@ def __import_kvset_from_file(client, path, yes):
10561064
user_confirmation('Do you want to continue?\n')
10571065

10581066
for config_setting in kvset_to_import:
1059-
if __is_key_vault_ref(kv=config_setting):
1060-
if not __validate_import_keyvault_ref(kv=config_setting):
1061-
continue
1062-
elif __is_feature_flag(kv=config_setting):
1063-
if not __validate_import_feature_flag(kv=config_setting):
1064-
continue
1065-
elif not validate_import_key(config_setting.key):
1066-
continue
1067-
1068-
# All validations successful
10691067
__write_configuration_setting_to_config_store(client, config_setting)
10701068

10711069

@@ -1103,6 +1101,42 @@ def __validate_import_feature_flag(kv):
11031101
return False
11041102

11051103

1104+
def __validate_import_config_setting(config_setting):
1105+
if __is_key_vault_ref(kv=config_setting):
1106+
if not __validate_import_keyvault_ref(kv=config_setting):
1107+
return False
1108+
elif __is_feature_flag(kv=config_setting):
1109+
if not __validate_import_feature_flag(kv=config_setting):
1110+
return False
1111+
elif not validate_import_key(config_setting.key):
1112+
return False
1113+
1114+
if config_setting.value and not isinstance(config_setting.value, str):
1115+
logger.warning("The 'value' for the key '{%s}' is not a string. This key-value will not be imported.", config_setting.key)
1116+
return False
1117+
if config_setting.content_type and not isinstance(config_setting.content_type, str):
1118+
logger.warning("The 'content_type' for the key '{%s}' is not a string. This key-value will not be imported.", config_setting.key)
1119+
return False
1120+
if config_setting.label and not isinstance(config_setting.label, str):
1121+
logger.warning("The 'label' for the key '{%s}' is not a string. This key-value will not be imported.", config_setting.key)
1122+
return False
1123+
1124+
return __validate_import_tags(config_setting)
1125+
1126+
1127+
def __validate_import_tags(kv):
1128+
if kv.tags and not isinstance(kv.tags, dict):
1129+
logger.warning("The format of 'tags' for key '%s' is not valid. This key-value will not be imported.", kv.key)
1130+
return False
1131+
1132+
if kv.tags:
1133+
for tag_key, tag_value in kv.tags.items():
1134+
if not isinstance(tag_value, str):
1135+
logger.warning("The value for the tag '{%s}' for key '{%s}' is not in a valid format. This key-value will not be imported.", tag_key, kv.key)
1136+
return False
1137+
return True
1138+
1139+
11061140
def __write_configuration_setting_to_config_store(azconfig_client, configuration_setting):
11071141
try:
11081142
azconfig_client.set_configuration_setting(configuration_setting)

0 commit comments

Comments
 (0)