From 23210528275790804925b4ee7b4d688c22cd9582 Mon Sep 17 00:00:00 2001 From: Adrian Galvan Date: Tue, 19 Nov 2024 12:27:44 -0800 Subject: [PATCH] Updating masking strict check to use config proxy (#5512) --- .../api/service/connectors/saas_connector.py | 4 ++- .../service/connectors/saas_query_config.py | 10 ++++--- src/fides/config/config_proxy.py | 1 + .../service/connectors/test_saas_connector.py | 12 +++++--- .../connectors/test_saas_queryconfig.py | 30 +++++++++++-------- 5 files changed, 36 insertions(+), 21 deletions(-) diff --git a/src/fides/api/service/connectors/saas_connector.py b/src/fides/api/service/connectors/saas_connector.py index 80ded10b76..588ac9265a 100644 --- a/src/fides/api/service/connectors/saas_connector.py +++ b/src/fides/api/service/connectors/saas_connector.py @@ -527,7 +527,9 @@ def mask_data( self.set_privacy_request_state(privacy_request, node, request_task) query_config = self.query_config(node) - masking_request = query_config.get_masking_request() + + session = Session.object_session(privacy_request) + masking_request = query_config.get_masking_request(session) if not masking_request: raise Exception( f"Either no masking request configured or no valid masking request for {node.address.collection}. " diff --git a/src/fides/api/service/connectors/saas_query_config.py b/src/fides/api/service/connectors/saas_query_config.py index 309d7b43fd..e72313a756 100644 --- a/src/fides/api/service/connectors/saas_query_config.py +++ b/src/fides/api/service/connectors/saas_query_config.py @@ -9,6 +9,7 @@ import pydash from fideslang.models import FidesDatasetReference from loguru import logger +from sqlalchemy.orm import Session from fides.api.common_exceptions import FidesopsException from fides.api.graph.config import ScalarField @@ -43,7 +44,7 @@ unflatten_dict, ) from fides.common.api.v1.urn_registry import REQUEST_TASK_CALLBACK, V1_URL_PREFIX -from fides.config import CONFIG +from fides.config.config_proxy import ConfigProxy T = TypeVar("T") @@ -131,7 +132,7 @@ def get_erasure_request_by_action( ) return request - def get_masking_request(self) -> Optional[SaaSRequest]: + def get_masking_request(self, db: Session) -> Optional[SaaSRequest]: """ Returns a tuple of the preferred action and SaaSRequest to use for masking. An update request is preferred, but we can use a gdpr delete endpoint or @@ -142,7 +143,7 @@ def get_masking_request(self) -> Optional[SaaSRequest]: gdpr_delete: Optional[SaaSRequest] = None delete: Optional[SaaSRequest] = None - if not CONFIG.execution.masking_strict: + if not ConfigProxy(db).execution.masking_strict: gdpr_delete = self.data_protection_request delete = self.get_erasure_request_by_action("delete") @@ -372,7 +373,8 @@ def generate_update_stmt( The fields in the row are masked according to the policy and added to the request body if specified by the body field of the masking request. """ - current_request: SaaSRequest = self.get_masking_request() # type: ignore + session = Session.object_session(request) + current_request: SaaSRequest = self.get_masking_request(session) # type: ignore param_values: Dict[str, Any] = self.generate_update_param_values( row, policy, request, current_request ) diff --git a/src/fides/config/config_proxy.py b/src/fides/config/config_proxy.py index 20a8d69daf..45e1bd70dd 100644 --- a/src/fides/config/config_proxy.py +++ b/src/fides/config/config_proxy.py @@ -106,6 +106,7 @@ class ExecutionSettingsProxy(ConfigProxyBase): subject_identity_verification_required: bool disable_consent_identity_verification: bool require_manual_request_approval: bool + masking_strict: bool def __getattribute__(self, name: str) -> Any: """ diff --git a/tests/ops/service/connectors/test_saas_connector.py b/tests/ops/service/connectors/test_saas_connector.py index 02efe14acc..5c1b941041 100644 --- a/tests/ops/service/connectors/test_saas_connector.py +++ b/tests/ops/service/connectors/test_saas_connector.py @@ -392,7 +392,11 @@ def test_missing_grouped_inputs_input_values( @mock.patch("fides.api.service.connectors.saas_connector.AuthenticatedClient.send") def test_skip_missing_param_values_masking( - self, mock_send: Mock, saas_example_config, saas_example_connection_config + self, + mock_send: Mock, + privacy_request, + saas_example_config, + saas_example_connection_config, ): """ Verifies skip_missing_param_values behavior for Connector.mask_data. @@ -424,7 +428,7 @@ def test_skip_missing_param_values_masking( connector.mask_data( execution_node, Policy(), - PrivacyRequest(id="123"), + privacy_request, request_task, [{"customer_id": 1}], ) @@ -441,7 +445,7 @@ def test_skip_missing_param_values_masking( connector.mask_data( execution_node, Policy(), - PrivacyRequest(id="123"), + privacy_request, request_task, [{"customer_id": 1}], ) @@ -454,7 +458,7 @@ def test_skip_missing_param_values_masking( connector.mask_data( execution_node, Policy(), - PrivacyRequest(id="123"), + privacy_request, request_task, [{"customer_id": 1}], ) diff --git a/tests/ops/service/connectors/test_saas_queryconfig.py b/tests/ops/service/connectors/test_saas_queryconfig.py index c74cf2619a..4a2e2b44e7 100644 --- a/tests/ops/service/connectors/test_saas_queryconfig.py +++ b/tests/ops/service/connectors/test_saas_queryconfig.py @@ -8,6 +8,7 @@ from fides.api.graph.config import CollectionAddress from fides.api.graph.graph import DatasetGraph from fides.api.graph.traversal import Traversal +from fides.api.models.application_config import ApplicationConfig from fides.api.models.connectionconfig import ConnectionConfig from fides.api.models.datasetconfig import DatasetConfig from fides.api.models.privacy_request import PrivacyRequest @@ -22,8 +23,6 @@ from fides.config import CONFIG from tests.ops.graph.graph_test_util import generate_node -privacy_request = PrivacyRequest(id="234544") - @pytest.mark.unit_saas class TestSaaSQueryConfig: @@ -189,6 +188,7 @@ def test_generate_requests( def test_generate_update_stmt( self, + privacy_request, erasure_policy_string_rewrite, combined_traversal, saas_example_connection_config, @@ -224,6 +224,7 @@ def test_generate_update_stmt( def test_generate_update_stmt_custom_http_method( self, + privacy_request, erasure_policy_string_rewrite, combined_traversal, saas_example_connection_config, @@ -262,6 +263,7 @@ def test_generate_update_stmt_custom_http_method( def test_generate_update_stmt_with_request_body( self, + privacy_request, erasure_policy_string_rewrite, combined_traversal, saas_example_connection_config, @@ -336,6 +338,7 @@ def test_generate_update_stmt_with_request_body( def test_generate_update_stmt_with_url_encoded_body( self, + privacy_request, erasure_policy_string_rewrite, combined_traversal, saas_example_connection_config, @@ -430,7 +433,7 @@ def test_get_read_requests_by_identity( assert len(saas_requests) == 2 def test_get_masking_request( - self, combined_traversal, saas_example_connection_config + self, db, combined_traversal, saas_example_connection_config ): saas_config: Optional[SaaSConfig] = ( saas_example_connection_config.get_saas_config() @@ -448,7 +451,7 @@ def test_get_masking_request( ] query_config = SaaSQueryConfig(member, endpoints, {}) - saas_request = query_config.get_masking_request() + saas_request = query_config.get_masking_request(db) # Assert we pulled the update method off of the member collection assert saas_request.method == "PUT" @@ -456,11 +459,11 @@ def test_get_masking_request( # No update methods defined on other collections query_config = SaaSQueryConfig(conversations, endpoints, {}) - saas_request = query_config.get_masking_request() + saas_request = query_config.get_masking_request(db) assert saas_request is None query_config = SaaSQueryConfig(messages, endpoints, {}) - saas_request = query_config.get_masking_request() + saas_request = query_config.get_masking_request(db) assert saas_request is None # Define delete request on conversations endpoint @@ -471,15 +474,16 @@ def test_get_masking_request( assert CONFIG.execution.masking_strict is True query_config = SaaSQueryConfig(conversations, endpoints, {}) - saas_request = query_config.get_masking_request() + saas_request = query_config.get_masking_request(db) assert saas_request is None # Override masking_strict to False - masking_strict = CONFIG.execution.masking_strict + original_value = CONFIG.execution.masking_strict CONFIG.execution.masking_strict = False + ApplicationConfig.update_config_set(db, CONFIG) # Now delete endpoint is selected as conversations masking request - saas_request: SaaSRequest = query_config.get_masking_request() + saas_request: SaaSRequest = query_config.get_masking_request(db) assert saas_request.path == "/api/0///" assert saas_request.method == "DELETE" @@ -490,12 +494,13 @@ def test_get_masking_request( ) # Assert GDPR Delete takes priority over Delete - saas_request: SaaSRequest = query_config.get_masking_request() + saas_request: SaaSRequest = query_config.get_masking_request(db) assert saas_request.path == "/api/0/gdpr_delete" assert saas_request.method == "PUT" # Reset - CONFIG.execution.masking_strict = masking_strict + CONFIG.notifications.enable_property_specific_messaging = original_value + ApplicationConfig.update_config_set(db, CONFIG) del endpoints["conversations"].requests.delete def test_list_param_values( @@ -651,6 +656,7 @@ def test_custom_privacy_request_fields( self, mock_identity_data: Mock, mock_custom_privacy_request_fields: Mock, + privacy_request, policy, consent_policy, erasure_policy_string_rewrite, @@ -676,7 +682,7 @@ def test_custom_privacy_request_fields( internal_information, endpoints, {}, - privacy_request=PrivacyRequest(id="123"), + privacy_request, ) read_request, param_value_map = config.generate_requests(