From 0bc1ac73a801ab0a83d1ba44c3cd3f8e44ade8eb Mon Sep 17 00:00:00 2001 From: Max Ustinov Date: Thu, 14 Sep 2023 16:14:26 -0700 Subject: [PATCH 1/7] Update Python SDK to version 16.6.2 and updates change log --- sdk/python/__init__.py | 0 sdk/python/core/README.md | 4 ++++ sdk/python/core/setup.py | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) delete mode 100644 sdk/python/__init__.py diff --git a/sdk/python/__init__.py b/sdk/python/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/sdk/python/core/README.md b/sdk/python/core/README.md index ae9dc72f..ea621114 100644 --- a/sdk/python/core/README.md +++ b/sdk/python/core/README.md @@ -4,6 +4,10 @@ For more information see our official documentation page https://docs.keeper.io/ # Change Log +## 16.6.2 +* KSM-463 - Python SDK - Fix a bug when fields is null +* KSM-458 - Python SDK - Remove core's dependency on the helper module. Fixes [issue 488](https://github.com/Keeper-Security/secrets-manager/issues/488) + ## 16.6.1 * KSM 444 - Python - Added folderUid and innerFolderUid to Record diff --git a/sdk/python/core/setup.py b/sdk/python/core/setup.py index 83287387..fba7b881 100644 --- a/sdk/python/core/setup.py +++ b/sdk/python/core/setup.py @@ -20,7 +20,7 @@ setup( name="keeper-secrets-manager-core", - version="16.6.1", + version="16.6.2", description="Keeper Secrets Manager for Python 3", long_description=long_description, long_description_content_type="text/markdown", From 5dc2d763df8cbd3c74035ea1bd56f198e233599a Mon Sep 17 00:00:00 2001 From: idimov-keeper <78815270+idimov-keeper@users.noreply.github.com> Date: Thu, 14 Sep 2023 18:16:59 -0500 Subject: [PATCH 2/7] KSM-463 - Python SDK - fix for record's data JSON where "fields": null (#525) * fix for record's data JSON where "fields": null * added test for clients that do not store "fields":[] or set it to null --- .../tests/misc_test.py | 2 +- .../tests/secret_test.py | 7 +- .../keeper_secrets_manager_core/dto/dtos.py | 2 + .../core/keeper_secrets_manager_core/mock.py | 2 +- sdk/python/core/tests/record_test.py | 91 ++++++++++++++----- 5 files changed, 76 insertions(+), 28 deletions(-) diff --git a/integration/keeper_secrets_manager_cli/tests/misc_test.py b/integration/keeper_secrets_manager_cli/tests/misc_test.py index c9cf87f3..fdbe4dc6 100644 --- a/integration/keeper_secrets_manager_cli/tests/misc_test.py +++ b/integration/keeper_secrets_manager_cli/tests/misc_test.py @@ -66,7 +66,7 @@ def test_config_mode_dog_food(self): sp = subprocess.run(["icacls.exe", Config.default_ini_file], capture_output=True) if sp.stderr is not None and sp.stderr.decode() != "": self.fail("Could not icacls.exe {}: {}".format(Config.default_ini_file,sp.stderr.decode())) - allowed_users = [user.lower(), "Administrators".lower()] + allowed_users = [user.decode().lower(), "Administrators".lower()] for line in sp.stdout.decode().split("\n"): parts = line[len(Config.default_ini_file):].split(":") if len(parts) == 2: diff --git a/integration/keeper_secrets_manager_cli/tests/secret_test.py b/integration/keeper_secrets_manager_cli/tests/secret_test.py index b187fc19..6c3dc57d 100644 --- a/integration/keeper_secrets_manager_cli/tests/secret_test.py +++ b/integration/keeper_secrets_manager_cli/tests/secret_test.py @@ -154,13 +154,13 @@ def test_get(self): # JSON Output w/ JQ to stdout runner = CliRunner() result = runner.invoke(cli, [ - 'secret', 'get', '-u', one.uid, '--json', + 'secret', 'get', '-u', one.uid, '--json', '--inflate', '--query', 'fields[*]' ], catch_exceptions=False) self.assertEqual(0, result.exit_code, "the exit code was not 0") fields = json.loads(result.output) - self.assertEqual(4, len(fields), "didn't find 4 objects in array") + self.assertEqual(6, len(fields), "didn't find 4 objects in array") # Text Output to file tf_name = self._make_temp_file() @@ -183,8 +183,9 @@ def test_get(self): result = runner.invoke(cli, [ 'secret', 'get', '-u', one.uid, '--query', '[*].fields[*].type', - '--force-array' + '--force-array', '--deflate', ], catch_exceptions=True) + print(f'result.output: {result.output}') # TODO: remove after test data = json.loads(result.output) self.assertEqual(4, len(data), "found 4 rows") self.assertEqual(0, result.exit_code, "the exit code was not 0") diff --git a/sdk/python/core/keeper_secrets_manager_core/dto/dtos.py b/sdk/python/core/keeper_secrets_manager_core/dto/dtos.py index f346393c..a71e425c 100644 --- a/sdk/python/core/keeper_secrets_manager_core/dto/dtos.py +++ b/sdk/python/core/keeper_secrets_manager_core/dto/dtos.py @@ -54,6 +54,8 @@ def __init__(self, record_dict, secret_key, folder_uid = ''): self.raw_json = record_data_json self.dict = utils.json_to_dict(self.raw_json) + if self.dict and self.dict.get('fields') is None: + self.dict['fields'] = [] self.title = self.dict.get('title') self.type = self.dict.get('type') self.revision = record_dict.get('revision') diff --git a/sdk/python/core/keeper_secrets_manager_core/mock.py b/sdk/python/core/keeper_secrets_manager_core/mock.py index ebe7b605..0665590b 100644 --- a/sdk/python/core/keeper_secrets_manager_core/mock.py +++ b/sdk/python/core/keeper_secrets_manager_core/mock.py @@ -390,7 +390,7 @@ def add_file(self, name, title=None, content_type=None, url=None, content=None, def dump(self, secret, flags=None): - fields = list(self._fields) + fields = self._fields # If no files, the JSON has null files = None diff --git a/sdk/python/core/tests/record_test.py b/sdk/python/core/tests/record_test.py index 0f36b53e..b5012d5d 100644 --- a/sdk/python/core/tests/record_test.py +++ b/sdk/python/core/tests/record_test.py @@ -1,6 +1,6 @@ -import unittest -import tempfile import os +import tempfile +import unittest from keeper_secrets_manager_core.storage import FileKeyValueStorage from keeper_secrets_manager_core import SecretsManager @@ -20,34 +20,40 @@ def tearDown(self): os.chdir(self.orig_working_dir) def test_the_login_record_password(self): - - """ If the record type is login, the password will be placed in the instance attribute. + """ If the record type is login, the password will be placed + in the instance attribute. """ try: with tempfile.NamedTemporaryFile("w", delete=False) as fh: fh.write(MockConfig.make_json()) fh.seek(0) - secrets_manager = SecretsManager(config=FileKeyValueStorage(config_file_location=fh.name)) + secrets_manager = SecretsManager( + config=FileKeyValueStorage(config_file_location=fh.name)) # A good record. - # 'fields': [...{'type': 'password', 'value': ['My Password']}...] + # 'fields':[{'type': 'password', 'value': ['My Password']}...] good_res = mock.Response() - good = good_res.add_record(title="Good Record", record_type='login') + good = good_res.add_record( + title="Good Record", record_type='login') good.field("login", "My Login") good.field("password", "My Password") - # A bad record. This would be like if someone removed a password text from an existing field. + # A bad record. This would be like if someone removed + # a password text from an existing field. # 'fields': [...{'type': 'password', 'value': []}...] bad_res = mock.Response() - bad = bad_res.add_record(title="Bad Record", record_type='login') + bad = bad_res.add_record( + title="Bad Record", record_type='login') bad.field("login", "My Login") bad.field("password", []) - # An ugly record. The application didn't even add the field. We need to set flags to prune empty fields. + # An ugly record. The application didn't even add the field. + # We need to set flags to prune empty fields. # 'fields': [...] ugly_res = mock.Response(flags={"prune_empty_fields": True}) - ugly = ugly_res.add_record(title="Ugly Record", record_type='login') + ugly = ugly_res.add_record( + title="Ugly Record", record_type='login') ugly.field("login", "My Login") # this will be removed from the fields array. @@ -59,16 +65,23 @@ def test_the_login_record_password(self): res_queue.add_response(ugly_res) records = secrets_manager.get_secrets() - self.assertEqual(1, len(records), "didn't get 1 record for the good") - self.assertEqual("My Password", records[0].password, "did not get correct password for the good") + self.assertEqual( + 1, len(records), "didn't get 1 record for the good") + self.assertEqual( + "My Password", records[0].password, + "did not get correct password for the good") records = secrets_manager.get_secrets() - self.assertEqual(1, len(records), "didn't get 1 record for the bad") - self.assertIsNone(records[0].password, "password is defined for the bad") + self.assertEqual( + 1, len(records), "didn't get 1 record for the bad") + self.assertIsNone(records[0].password, + "password is defined for the bad") records = secrets_manager.get_secrets() - self.assertEqual(1, len(records), "didn't get 1 record for the ugly") - self.assertIsNone(records[0].password, "password is defined for the ugly") + self.assertEqual( + 1, len(records), "didn't get 1 record for the ugly") + self.assertIsNone(records[0].password, + "password is defined for the ugly") finally: try: os.unlink(fh.name) @@ -77,7 +90,8 @@ def test_the_login_record_password(self): def test_record_field(self): - rf = RecordField(field_type="login", value="test", label="Test", required=True, enforceGeneration=False, + rf = RecordField(field_type="login", value="test", label="Test", + required=True, enforceGeneration=False, privacyScreen=True, complexity={"foo": "bar"}) value = helpers.obj_to_dict(rf) @@ -85,9 +99,12 @@ def test_record_field(self): self.assertEqual(["test"], value.get("value"), "value is not correct") self.assertEqual("Test", value.get("label"), "label is not correct") self.assertTrue(value.get("required"), "required is not correct") - self.assertFalse(value.get("enforceGeneration"), "enforceGeneration is not correct") - self.assertTrue(value.get("privacyScreen"), "privacyScreen is not correct") - self.assertIsNotNone(value.get("complexity"), "complexity is not correct") + self.assertFalse(value.get("enforceGeneration"), + "enforceGeneration is not correct") + self.assertTrue(value.get("privacyScreen"), + "privacyScreen is not correct") + self.assertIsNotNone(value.get("complexity"), + "complexity is not correct") rf = RecordField(field_type="login", value="test", privacyScreen=None) @@ -96,7 +113,35 @@ def test_record_field(self): self.assertEqual(["test"], value.get("value"), "value is not correct") self.assertIsNone(value.get("label"), "label is not correct") self.assertIsNone(value.get("required"), "required is not correct") - self.assertIsNone(value.get("enforceGeneration"), "enforceGeneration is not correct") + self.assertIsNone(value.get("enforceGeneration"), + "enforceGeneration is not correct") assert "privacyScreen" not in value, "privacyScreen exists in dictionary" - self.assertIsNone(value.get("privacyScreen"), "privacyScreen is not correct") + self.assertIsNone(value.get("privacyScreen"), + "privacyScreen is not correct") self.assertIsNone(value.get("complexity"), "complexity is not correct") + + def test_missing_fields_section(self): + """ Test for clients that may set "fields": null in JSON data """ + + try: + with tempfile.NamedTemporaryFile("w", delete=False) as fh: + fh.write(MockConfig.make_json()) + fh.seek(0) + secrets_manager = SecretsManager( + config=FileKeyValueStorage(config_file_location=fh.name)) + + res = mock.Response() + rec = res.add_record(title="MyLogin", record_type='login') + res.records[rec.uid]._fields = None + res_queue = mock.ResponseQueue(client=secrets_manager) + res_queue.add_response(res) + + records = secrets_manager.get_secrets() + self.assertEqual( + 1, len(records), "didn't get 1 record for MyLogin") + self.assertEqual([], records[0].dict.get('fields')) + finally: + try: + os.unlink(fh.name) + except OSError: + pass From 93034b6e96c6c78ce3349e374d06723a2a30b965 Mon Sep 17 00:00:00 2001 From: John Walstra <98108730+jwalstra-keeper@users.noreply.github.com> Date: Thu, 14 Sep 2023 18:29:41 -0500 Subject: [PATCH 3/7] KSM-458 - Python SDK - remove core dep on helper (#519) * KSM-440 Ansible Cache Records Created a new Ansible action to retrieve records from the Vault and create a encrypted serialized cache. This cache can then be set on the attributes of the existing action. If set, the existing actions will use the records in the cache. However, if the action uses notation, the cache will not work. The KSM SDK notation method needs to be changed to allow a list of Record to be passed in. Right now it always get record from the Keeper Vault. The new action `keeper_cache_records` takes a list of UID and/or titles. ```yaml tasks: - name: Generate a Keeper Record Cache secret keeper_password: length: 64 register: keeper_record_cache_secret no_log: True - name: Store the Keeper Record Cache secret into variables. set_fact: keeper_record_cache_secret: "{{ keeper_record_cache_secret.password }}" no_log: True - name: Cache records. Will use keeper_record_cache_secret from above. keeper_cache_records: uids: - RECORD UID 1 - RECORD UID 2 titles: - TITLE 1 - TITLE 2 register: my_records no_log: True - name: "Get Value By UID" keeper_get: cache: "{{ my_records.cache }}" uid: RECORD UID 1 field: "password" register: "my_password_by_uid" ``` Bonus changes * Added the ability to select records by title to the `keeper_get`, `keeper_set`, and `keeper_copy` actions. * Added a non-notation selectors for complex field values. The attributes `array_index` and `value_key` allow selecting which object/value in an array and key/value pair for dictionaries. * Updated the test framework. Changes in Ansible broke our test framework. * KSM-458 Remove core dep on helper module Refactor add_custom_field not to use the helper module. The method will accept an instance of FieldType, however it is not tied to the keeper_secrets_manager_helper.v3.field_type.FieldType module. Allow the ability to set the type, label, and value not using the FieldType instance. The method will still take the param `field`, however it will also take `field_type`, `label`, and `value`. This allows adding a custom field without have to use the helper module. Removed references `keeper-secrets-manager-helper` from setup.py and requirements.txt. This should break the circular reference. Added unit tests for the method. --------- Co-authored-by: Max Ustinov --- .../keeper_secrets_manager_core/dto/dtos.py | 33 +++++-- sdk/python/core/requirements.txt | 1 - sdk/python/core/setup.py | 1 - sdk/python/core/tests/record_test.py | 85 +++++++++++++++++++ 4 files changed, 109 insertions(+), 11 deletions(-) diff --git a/sdk/python/core/keeper_secrets_manager_core/dto/dtos.py b/sdk/python/core/keeper_secrets_manager_core/dto/dtos.py index a71e425c..07cd7513 100644 --- a/sdk/python/core/keeper_secrets_manager_core/dto/dtos.py +++ b/sdk/python/core/keeper_secrets_manager_core/dto/dtos.py @@ -18,7 +18,6 @@ from keeper_secrets_manager_core import utils, helpers from keeper_secrets_manager_core.crypto import CryptoUtils from keeper_secrets_manager_core.exceptions import KeeperError -from keeper_secrets_manager_helper.v3.field_type import FieldType class Record: @@ -186,16 +185,32 @@ def set_custom_field_value(self, field_type, value): field["value"] = value self._update() - def add_custom_field(self, field: FieldType) -> bool: - if issubclass(type(field), FieldType): - if self.dict.get('custom', None) is None: - self.dict['custom'] = [] - custom = self.dict['custom'] + def add_custom_field(self, field=None, field_type=None, label=None, value=None) -> bool: + if self.dict.get('custom', None) is None: + self.dict['custom'] = [] + custom = self.dict['custom'] + + # Make backward compatible. Assumes keeper_secrets_manager_helper.v#.field_type.FieldType is passed in. + if field is not None: + if field.__class__.__name__ != "FieldType": + raise ValueError("The field is not an instance of FieldType") fdict = field.to_dict() custom.append(fdict) - self._update() - return True - return False + else: + if field_type is None: + return False + if isinstance(value, list) is False: + value = [value] + field_dict = { + "type": field_type, + "value": value + } + if label is not None: + field_dict["label"] = label + custom.append(field_dict) + + self._update() + return True # TODO: Deprecate this for better getter and setters def field(self, field_type, value=None, single=False): diff --git a/sdk/python/core/requirements.txt b/sdk/python/core/requirements.txt index b4d72fb0..f4a996a1 100644 --- a/sdk/python/core/requirements.txt +++ b/sdk/python/core/requirements.txt @@ -1,4 +1,3 @@ -keeper-secrets-manager-helper>=1.0.4 ecdsa cryptography>=39.0.1 requests>=2.28.2 diff --git a/sdk/python/core/setup.py b/sdk/python/core/setup.py index fba7b881..f77c050b 100644 --- a/sdk/python/core/setup.py +++ b/sdk/python/core/setup.py @@ -11,7 +11,6 @@ long_description = fp.read() install_requires = [ - 'keeper-secrets-manager-helper>=1.0.4', 'ecdsa', 'requests', 'cryptography>=39.0.1', diff --git a/sdk/python/core/tests/record_test.py b/sdk/python/core/tests/record_test.py index b5012d5d..050748f3 100644 --- a/sdk/python/core/tests/record_test.py +++ b/sdk/python/core/tests/record_test.py @@ -120,6 +120,91 @@ def test_record_field(self): "privacyScreen is not correct") self.assertIsNone(value.get("complexity"), "complexity is not correct") + def test_add_custom_field_by_param(self): + + try: + with tempfile.NamedTemporaryFile("w", delete=False) as fh: + fh.write(MockConfig.make_json()) + fh.seek(0) + secrets_manager = SecretsManager(config=FileKeyValueStorage(config_file_location=fh.name)) + + res = mock.Response() + mock_record = res.add_record(title="Good Record", record_type='login') + mock_record.field("login", "My Login") + mock_record.field("password", "My Password") + + res_queue = mock.ResponseQueue(client=secrets_manager) + res_queue.add_response(res) + + records = secrets_manager.get_secrets() + record = records[0] + + record.add_custom_field( + field_type='text', + label="My Label", + value="My Value" + ) + new_value = record.get_custom_field("My Label") + self.assertEqual("text", new_value.get("type")) + self.assertEqual("My Label", new_value.get("label")) + self.assertEqual(['My Value'], new_value.get("value")) + finally: + try: + os.unlink(fh.name) + except OSError: + pass + + def test_add_custom_field_by_field_type(self): + + class FieldType: + + def __init__(self, field_type, label, value): + self.field_type = field_type + self.label = label + self.value = value + + def to_dict(self): + return { + "type": self.field_type, + "label": self.label, + "value": self.value + } + + try: + with tempfile.NamedTemporaryFile("w", delete=False) as fh: + fh.write(MockConfig.make_json()) + fh.seek(0) + secrets_manager = SecretsManager(config=FileKeyValueStorage(config_file_location=fh.name)) + + res = mock.Response() + mock_record = res.add_record(title="Good Record", record_type='login') + mock_record.field("login", "My Login") + mock_record.field("password", "My Password") + + res_queue = mock.ResponseQueue(client=secrets_manager) + res_queue.add_response(res) + + records = secrets_manager.get_secrets() + record = records[0] + + field = FieldType( + field_type="text", + label="My Label", + value=["My Value"] + ) + + record.add_custom_field(field=field) + + new_value = record.get_custom_field("My Label") + self.assertEqual("text", new_value.get("type")) + self.assertEqual("My Label", new_value.get("label")) + self.assertEqual(['My Value'], new_value.get("value")) + finally: + try: + os.unlink(fh.name) + except OSError: + pass + def test_missing_fields_section(self): """ Test for clients that may set "fields": null in JSON data """ From 375bf953982f52d07c2d262c347ff7d1b8fe16e4 Mon Sep 17 00:00:00 2001 From: Max Ustinov Date: Thu, 14 Sep 2023 16:40:53 -0700 Subject: [PATCH 4/7] Ksm 463 fix a bug when fields is null in python sdk (#528) * fix for record's data JSON where "fields": null added test for clients that do not store "fields":[] or set it to null * auto-format record tests --- integration/keeper_secrets_manager_cli/tests/secret_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/keeper_secrets_manager_cli/tests/secret_test.py b/integration/keeper_secrets_manager_cli/tests/secret_test.py index 6c3dc57d..92b532c3 100644 --- a/integration/keeper_secrets_manager_cli/tests/secret_test.py +++ b/integration/keeper_secrets_manager_cli/tests/secret_test.py @@ -160,7 +160,7 @@ def test_get(self): self.assertEqual(0, result.exit_code, "the exit code was not 0") fields = json.loads(result.output) - self.assertEqual(6, len(fields), "didn't find 4 objects in array") + self.assertEqual(6, len(fields), "didn't find 6 objects in array") # Text Output to file tf_name = self._make_temp_file() From df1016771131462411d7056233863f06adac34e2 Mon Sep 17 00:00:00 2001 From: Max Ustinov Date: Fri, 15 Sep 2023 13:45:21 -0700 Subject: [PATCH 5/7] KSM CLI: Adjusted handling of empty _fields in Keeper Secrets Manager Adjusted the dump method in Keeper Secrets Manager's mock.py to account for empty _fields variable, preventing a NoneType error. Updated the unit tests in secret_test.py to align with these changes, reducing the expected length of fields from 6 to 4 and adjusting the index of field from 1 to 0. Also, removed unnecessary print statement in the test. This ensures that tests correctly correspond to the application code and avoid false negatives. --- integration/keeper_secrets_manager_cli/tests/secret_test.py | 5 ++--- sdk/python/core/keeper_secrets_manager_core/mock.py | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/integration/keeper_secrets_manager_cli/tests/secret_test.py b/integration/keeper_secrets_manager_cli/tests/secret_test.py index 92b532c3..d1a2bc26 100644 --- a/integration/keeper_secrets_manager_cli/tests/secret_test.py +++ b/integration/keeper_secrets_manager_cli/tests/secret_test.py @@ -160,7 +160,7 @@ def test_get(self): self.assertEqual(0, result.exit_code, "the exit code was not 0") fields = json.loads(result.output) - self.assertEqual(6, len(fields), "didn't find 6 objects in array") + self.assertEqual(4, len(fields), "didn't find 4 objects in array") # Text Output to file tf_name = self._make_temp_file() @@ -185,7 +185,6 @@ def test_get(self): '--query', '[*].fields[*].type', '--force-array', '--deflate', ], catch_exceptions=True) - print(f'result.output: {result.output}') # TODO: remove after test data = json.loads(result.output) self.assertEqual(4, len(data), "found 4 rows") self.assertEqual(0, result.exit_code, "the exit code was not 0") @@ -959,7 +958,7 @@ def test_template_record_types(self): self.assertIsInstance(data.get("fields"), list, "fields is not a list") - field = data.get("fields")[1] + field = data.get("fields")[0] self.assertEqual("login", field.get("type"), "field type is not login") self.assertIsNotNone(field.get("value"), "value was None") diff --git a/sdk/python/core/keeper_secrets_manager_core/mock.py b/sdk/python/core/keeper_secrets_manager_core/mock.py index 0665590b..244dc8b6 100644 --- a/sdk/python/core/keeper_secrets_manager_core/mock.py +++ b/sdk/python/core/keeper_secrets_manager_core/mock.py @@ -390,7 +390,7 @@ def add_file(self, name, title=None, content_type=None, url=None, content=None, def dump(self, secret, flags=None): - fields = self._fields + fields = self._fields if self._fields else [] # If no files, the JSON has null files = None From 83f29e3c9bc2f228fc57745b15ef507f632a72cb Mon Sep 17 00:00:00 2001 From: Max Ustinov Date: Fri, 15 Sep 2023 14:08:37 -0700 Subject: [PATCH 6/7] Modify dump method and test commands Revised the dump method in keeper_secrets_manager_core/mock.py to handle non-list types of self._fields properly. Also modified test commands in secret_test.py, removing '--inflate' and '--deflate' flags to accurately reflect the current functionality. Adjustments in test and core functions are necessary to ensure aligned and accurate testing, and to handle various data types in the dump method. --- integration/keeper_secrets_manager_cli/tests/secret_test.py | 4 ++-- sdk/python/core/keeper_secrets_manager_core/mock.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/integration/keeper_secrets_manager_cli/tests/secret_test.py b/integration/keeper_secrets_manager_cli/tests/secret_test.py index d1a2bc26..0bcf0e15 100644 --- a/integration/keeper_secrets_manager_cli/tests/secret_test.py +++ b/integration/keeper_secrets_manager_cli/tests/secret_test.py @@ -154,7 +154,7 @@ def test_get(self): # JSON Output w/ JQ to stdout runner = CliRunner() result = runner.invoke(cli, [ - 'secret', 'get', '-u', one.uid, '--json', '--inflate', + 'secret', 'get', '-u', one.uid, '--json', '--query', 'fields[*]' ], catch_exceptions=False) @@ -183,7 +183,7 @@ def test_get(self): result = runner.invoke(cli, [ 'secret', 'get', '-u', one.uid, '--query', '[*].fields[*].type', - '--force-array', '--deflate', + '--force-array' ], catch_exceptions=True) data = json.loads(result.output) self.assertEqual(4, len(data), "found 4 rows") diff --git a/sdk/python/core/keeper_secrets_manager_core/mock.py b/sdk/python/core/keeper_secrets_manager_core/mock.py index 244dc8b6..81889c58 100644 --- a/sdk/python/core/keeper_secrets_manager_core/mock.py +++ b/sdk/python/core/keeper_secrets_manager_core/mock.py @@ -390,7 +390,7 @@ def add_file(self, name, title=None, content_type=None, url=None, content=None, def dump(self, secret, flags=None): - fields = self._fields if self._fields else [] + fields = list(self._fields) if isinstance(self._fields, list) else self._fields # If no files, the JSON has null files = None From 78ed1c323eeacc687409461ce3d8c9763774f7db Mon Sep 17 00:00:00 2001 From: Max Ustinov Date: Fri, 15 Sep 2023 14:12:58 -0700 Subject: [PATCH 7/7] KSM CLI: Use second element in "fields" list in secret_test.py Changed access index from 0 to 1 while fetching "fields" list in secret_test.py, under the assertion tests. This change is due to adjustments made in the application code where the first element could possibly be None, hence to prevent False negatives and maintaining the relevance of tests, this index shift was necessary. --- integration/keeper_secrets_manager_cli/tests/secret_test.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/integration/keeper_secrets_manager_cli/tests/secret_test.py b/integration/keeper_secrets_manager_cli/tests/secret_test.py index 0bcf0e15..b187fc19 100644 --- a/integration/keeper_secrets_manager_cli/tests/secret_test.py +++ b/integration/keeper_secrets_manager_cli/tests/secret_test.py @@ -958,7 +958,7 @@ def test_template_record_types(self): self.assertIsInstance(data.get("fields"), list, "fields is not a list") - field = data.get("fields")[0] + field = data.get("fields")[1] self.assertEqual("login", field.get("type"), "field type is not login") self.assertIsNotNone(field.get("value"), "value was None")