From 95098e5987f4232721fd898b762f71e07955a360 Mon Sep 17 00:00:00 2001 From: Seshu Brahma Date: Mon, 29 Jan 2024 11:48:55 -0800 Subject: [PATCH] Removed fields param from enc+dec methods --- .../utilities/data_masking/base.py | 16 ++-- .../utilities/data_masking/provider/base.py | 10 +-- .../e2e/data_masking/test_e2e_data_masking.py | 2 +- .../data_masking/test_aws_encryption_sdk.py | 79 ++++++++----------- .../data_masking/test_unit_data_masking.py | 26 +++--- 5 files changed, 62 insertions(+), 71 deletions(-) diff --git a/aws_lambda_powertools/utilities/data_masking/base.py b/aws_lambda_powertools/utilities/data_masking/base.py index da086de9d1e..91b60f36a30 100644 --- a/aws_lambda_powertools/utilities/data_masking/base.py +++ b/aws_lambda_powertools/utilities/data_masking/base.py @@ -38,7 +38,7 @@ def lambda_handler(event, context): "sensitive": "password" } - masked = masker.mask(data,fields=["sensitive"]) + masked = masker.erase(data,fields=["sensitive"]) return masked @@ -60,7 +60,7 @@ def __init__( def encrypt( self, data: dict, - fields: list[str], + fields: None = None, provider_options: dict | None = None, **encryption_context: str, ) -> dict: @@ -107,23 +107,23 @@ def decrypt( ) @overload - def mask(self, data, fields: None) -> str: + def erase(self, data, fields: None) -> str: ... @overload - def mask(self, data: list, fields: list[str]) -> list[str]: + def erase(self, data: list, fields: list[str]) -> list[str]: ... @overload - def mask(self, data: tuple, fields: list[str]) -> tuple[str]: + def erase(self, data: tuple, fields: list[str]) -> tuple[str]: ... @overload - def mask(self, data: dict, fields: list[str]) -> dict: + def erase(self, data: dict, fields: list[str]) -> dict: ... - def mask(self, data: Sequence | Mapping, fields: list[str] | None = None) -> str | list[str] | tuple[str] | dict: - return self._apply_action(data=data, fields=fields, action=self.provider.mask) + def erase(self, data: Sequence | Mapping, fields: list[str] | None = None) -> str | list[str] | tuple[str] | dict: + return self._apply_action(data=data, fields=fields, action=self.provider.erase) def _apply_action( self, diff --git a/aws_lambda_powertools/utilities/data_masking/provider/base.py b/aws_lambda_powertools/utilities/data_masking/provider/base.py index 23958f90eba..1f894c9c169 100644 --- a/aws_lambda_powertools/utilities/data_masking/provider/base.py +++ b/aws_lambda_powertools/utilities/data_masking/provider/base.py @@ -24,7 +24,7 @@ def encrypt(self, data) -> str: def decrypt(self, data) -> Any: # Implementation logic for data decryption - def mask(self, data) -> Union[str, Iterable]: + def erase(self, data) -> Union[str, Iterable]: # Implementation logic for data masking pass @@ -63,14 +63,14 @@ def decrypt(self, data, provider_options: dict | None = None, **encryption_conte """ raise NotImplementedError("Subclasses must implement decrypt()") - def mask(self, data, **kwargs) -> Iterable[str]: + def erase(self, data, **kwargs) -> Iterable[str]: """ - This method irreversibly masks data. + This method irreversibly erases data. - If the data to be masked is of type `str`, `dict`, or `bytes`, + If the data to be erased is of type `str`, `dict`, or `bytes`, this method will return a masked string, i.e. "*****". - If the data to be masked is of an iterable type like `list`, `tuple`, + If the data to be erased is of an iterable type like `list`, `tuple`, or `set`, this method will return a new object of the same type as the input data but with each element replaced by the string "*****". """ diff --git a/tests/e2e/data_masking/test_e2e_data_masking.py b/tests/e2e/data_masking/test_e2e_data_masking.py index 5664858d5d8..dfa8504a3c9 100644 --- a/tests/e2e/data_masking/test_e2e_data_masking.py +++ b/tests/e2e/data_masking/test_e2e_data_masking.py @@ -11,7 +11,7 @@ ) from tests.e2e.utils import data_fetcher -pytest.skip(reason="Data masking tests disabled until we go GA.", allow_module_level=True) +# pytest.skip(reason="Data masking tests disabled until we go GA.", allow_module_level=True) @pytest.fixture diff --git a/tests/functional/data_masking/test_aws_encryption_sdk.py b/tests/functional/data_masking/test_aws_encryption_sdk.py index 7dc594b2db8..cda6437f67f 100644 --- a/tests/functional/data_masking/test_aws_encryption_sdk.py +++ b/tests/functional/data_masking/test_aws_encryption_sdk.py @@ -51,7 +51,7 @@ def test_mask_int(data_masker): # GIVEN an int data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask(42) + masked_string = data_masker.erase(42) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -61,7 +61,7 @@ def test_mask_float(data_masker): # GIVEN a float data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask(4.2) + masked_string = data_masker.erase(4.2) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -71,7 +71,7 @@ def test_mask_bool(data_masker): # GIVEN a bool data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask(True) + masked_string = data_masker.erase(True) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -81,7 +81,7 @@ def test_mask_none(data_masker): # GIVEN a None data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask(None) + masked_string = data_masker.erase(None) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -91,7 +91,7 @@ def test_mask_str(data_masker): # GIVEN a str data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask("this is a string") + masked_string = data_masker.erase("this is a string") # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -101,7 +101,7 @@ def test_mask_list(data_masker): # GIVEN a list data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask([1, 2, "string", 3]) + masked_string = data_masker.erase([1, 2, "string", 3]) # THEN the result is the data masked, while maintaining type list assert masked_string == [DATA_MASKING_STRING, DATA_MASKING_STRING, DATA_MASKING_STRING, DATA_MASKING_STRING] @@ -117,7 +117,7 @@ def test_mask_dict(data_masker): } # WHEN mask is called with no fields argument - masked_string = data_masker.mask(data) + masked_string = data_masker.erase(data) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -133,7 +133,7 @@ def test_mask_dict_with_fields(data_masker): } # WHEN mask is called with a list of fields specified - masked_string = data_masker.mask(data, fields=["a.'1'.None", "a..'4'"]) + masked_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"]) # THEN the result is only the specified fields are masked assert masked_string == { @@ -156,7 +156,7 @@ def test_mask_json_dict_with_fields(data_masker): ) # WHEN mask is called with a list of fields specified - masked_json_string = data_masker.mask(data, fields=["a.'1'.None", "a..'4'"]) + masked_json_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"]) # THEN the result is only the specified fields are masked assert masked_json_string == { @@ -260,8 +260,8 @@ def test_encrypt_dict_with_fields(data_masker): } # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=["a.'1'.None", "a..'4'"]) - decrypted_data = data_masker.decrypt(encrypted_data, fields=["a.'1'.None", "a..'4'"]) + encrypted_data = data_masker.encrypt(data) + decrypted_data = data_masker.decrypt(encrypted_data) # THEN the result is only the specified fields are masked assert decrypted_data == data @@ -279,11 +279,11 @@ def test_encrypt_json_dict_with_fields(data_masker): ) # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=["a.'1'.None", "a..'4'"]) - decrypted_data = data_masker.decrypt(encrypted_data, fields=["a.'1'.None", "a..'4'"]) + encrypted_data = data_masker.encrypt(data) + decrypted_data = data_masker.decrypt(encrypted_data) # THEN the result is only the specified fields are masked - assert decrypted_data == json.loads(data) + assert decrypted_data == data def test_encrypt_json_with_list_fields(data_masker): @@ -297,13 +297,12 @@ def test_encrypt_json_with_list_fields(data_masker): }, ) - fields_operation = ["payload.first[0]", "payload.second[0].key1[0]"] # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=fields_operation) - decrypted_data = data_masker.decrypt(encrypted_data, fields=fields_operation) + encrypted_data = data_masker.encrypt(data) + decrypted_data = data_masker.decrypt(encrypted_data) # THEN the result is only the specified fields are masked - assert decrypted_data == json.loads(data) + assert decrypted_data == data def test_encrypt_json_with_tuple_fields(data_masker): @@ -317,14 +316,12 @@ def test_encrypt_json_with_tuple_fields(data_masker): }, ) - fields_operation = ["payload.first[0]", "payload.second[0]"] # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=fields_operation) - decrypted_data = data_masker.decrypt(encrypted_data, fields=fields_operation) + encrypted_data = data_masker.encrypt(data) + decrypted_data = data_masker.decrypt(encrypted_data) # THEN the result is only the specified fields are masked - assert decrypted_data == json.loads(data) - + assert decrypted_data == data def test_encrypt_with_encryption_context(data_masker): # GIVEN the data type is a json representation of a dictionary with a list inside @@ -337,13 +334,12 @@ def test_encrypt_with_encryption_context(data_masker): }, ) - fields_operation = ["payload.first[0]", "payload.second[0]"] # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=fields_operation, data_classification="confidential") - decrypted_data = data_masker.decrypt(encrypted_data, fields=fields_operation, data_classification="confidential") + encrypted_data = data_masker.encrypt(data, data_classification="confidential") + decrypted_data = data_masker.decrypt(encrypted_data, data_classification="confidential") # THEN the result is only the specified fields are masked - assert decrypted_data == json.loads(data) + assert decrypted_data == data def test_encrypt_with_complex_dict(data_masker): @@ -376,14 +372,12 @@ def test_encrypt_with_complex_dict(data_masker): }, ) - fields_operation = ["address[*].postcode"] # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=fields_operation) - decrypted_data = data_masker.decrypt(encrypted_data, fields=fields_operation) + encrypted_data = data_masker.encrypt(data) + decrypted_data = data_masker.decrypt(encrypted_data) # THEN the result is only the specified fields are masked - assert decrypted_data == json.loads(data) - + assert decrypted_data == data def test_encrypt_with_slice(data_masker): # GIVEN the data type is a json representation of a dictionary with a list inside @@ -415,13 +409,12 @@ def test_encrypt_with_slice(data_masker): }, ) - fields_operation = ["address[-1]"] # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=fields_operation) - decrypted_data = data_masker.decrypt(encrypted_data, fields=fields_operation) + encrypted_data = data_masker.encrypt(data) + decrypted_data = data_masker.decrypt(encrypted_data) # THEN the result is only the specified fields are masked - assert decrypted_data == json.loads(data) + assert decrypted_data == data def test_encrypt_with_complex_search(data_masker): @@ -454,13 +447,12 @@ def test_encrypt_with_complex_search(data_masker): }, ) - fields_operation = ["$.address[?(@.postcode > 81847)]"] # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=fields_operation) - decrypted_data = data_masker.decrypt(encrypted_data, fields=["address[1:3]"]) + encrypted_data = data_masker.encrypt(data) + decrypted_data = data_masker.decrypt(encrypted_data) # THEN the result is only the specified fields are masked - assert decrypted_data == json.loads(data) + assert decrypted_data == data def test_encrypt_with_provider_options(data_masker): # GIVEN the data type is a json representation of a dictionary with a list inside @@ -473,11 +465,10 @@ def test_encrypt_with_provider_options(data_masker): }, ) - fields_operation = ["payload.first[0]", "payload.second[0]"] provider_options = {"algorithm": Algorithm.AES_256_GCM_HKDF_SHA512_COMMIT_KEY} # WHEN encrypting and then decrypting the encrypted data - encrypted_data = data_masker.encrypt(data, fields=fields_operation, provider_options=provider_options) - decrypted_data = data_masker.decrypt(encrypted_data, fields=fields_operation) + encrypted_data = data_masker.encrypt(data, provider_options=provider_options) + decrypted_data = data_masker.decrypt(encrypted_data) # THEN the result is only the specified fields are masked - assert decrypted_data == json.loads(data) + assert decrypted_data == data \ No newline at end of file diff --git a/tests/unit/data_masking/test_unit_data_masking.py b/tests/unit/data_masking/test_unit_data_masking.py index 552abab4161..350c9f01eb0 100644 --- a/tests/unit/data_masking/test_unit_data_masking.py +++ b/tests/unit/data_masking/test_unit_data_masking.py @@ -19,7 +19,7 @@ def test_mask_int(data_masker): # GIVEN an int data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask(42) + masked_string = data_masker.erase(42) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -29,7 +29,7 @@ def test_mask_float(data_masker): # GIVEN a float data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask(4.2) + masked_string = data_masker.erase(4.2) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -39,7 +39,7 @@ def test_mask_bool(data_masker): # GIVEN a bool data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask(True) + masked_string = data_masker.erase(True) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -49,7 +49,7 @@ def test_mask_none(data_masker): # GIVEN a None data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask(None) + masked_string = data_masker.erase(None) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -59,7 +59,7 @@ def test_mask_str(data_masker): # GIVEN a str data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask("this is a string") + masked_string = data_masker.erase("this is a string") # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -69,7 +69,7 @@ def test_mask_list(data_masker): # GIVEN a list data type # WHEN mask is called with no fields argument - masked_string = data_masker.mask([1, 2, "string", 3]) + masked_string = data_masker.erase([1, 2, "string", 3]) # THEN the result is the data masked, while maintaining type list assert masked_string == [DATA_MASKING_STRING, DATA_MASKING_STRING, DATA_MASKING_STRING, DATA_MASKING_STRING] @@ -85,7 +85,7 @@ def test_mask_dict(data_masker): } # WHEN mask is called with no fields argument - masked_string = data_masker.mask(data) + masked_string = data_masker.erase(data) # THEN the result is the data masked assert masked_string == DATA_MASKING_STRING @@ -101,7 +101,7 @@ def test_mask_dict_with_fields(data_masker): } # WHEN mask is called with a list of fields specified - masked_string = data_masker.mask(data, fields=["a.'1'.None", "a..'4'"]) + masked_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"]) # THEN the result is only the specified fields are masked assert masked_string == { @@ -124,7 +124,7 @@ def test_mask_json_dict_with_fields(data_masker): ) # WHEN mask is called with a list of fields specified - masked_json_string = data_masker.mask(data, fields=["a.'1'.None", "a..'4'"]) + masked_json_string = data_masker.erase(data, fields=["a.'1'.None", "a..'4'"]) # THEN the result is only the specified fields are masked assert masked_json_string == { @@ -159,7 +159,7 @@ def test_parsing_unsupported_data_type(data_masker): # WHEN attempting to pass in a list of fields with input data that is not a dict with pytest.raises(DataMaskingUnsupportedTypeError): # THEN the result is a TypeError - data_masker.mask(42, ["this.field"]) + data_masker.erase(42, ["this.field"]) def test_parsing_with_empty_field(data_masker): @@ -168,7 +168,7 @@ def test_parsing_with_empty_field(data_masker): # WHEN attempting to pass in a list of fields with input data that is not a dict with pytest.raises(ValueError): # THEN the result is a TypeError - data_masker.mask(42, []) + data_masker.erase(42, []) def test_parsing_nonexistent_fields_with_raise_on_missing_field(): @@ -185,7 +185,7 @@ def test_parsing_nonexistent_fields_with_raise_on_missing_field(): # WHEN attempting to pass in fields that do not exist in the input data with pytest.raises(DataMaskingFieldNotFoundError): # THEN the result is a KeyError - data_masker.mask(data, ["'3'..True"]) + data_masker.erase(data, ["'3'..True"]) def test_parsing_nonexistent_fields_warning_on_missing_field(): @@ -201,7 +201,7 @@ def test_parsing_nonexistent_fields_warning_on_missing_field(): # WHEN mask is called with a non-existing field with pytest.warns(UserWarning, match="Field or expression*"): - masked_json_string = data_masker.mask(data, fields=["non-existing"]) + masked_json_string = data_masker.erase(data, fields=["non-existing"]) # THEN the "masked" payload is the same of the original assert masked_json_string == data