ethyca-fides 2.71.1b0__py2.py3-none-any.whl → 2.71.1rc0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ethyca-fides might be problematic. Click here for more details.
- {ethyca_fides-2.71.1b0.dist-info → ethyca_fides-2.71.1rc0.dist-info}/METADATA +2 -2
- {ethyca_fides-2.71.1b0.dist-info → ethyca_fides-2.71.1rc0.dist-info}/RECORD +165 -151
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/3efe14d4469a_adds_new_experience_configs_for_vendor_.py +79 -0
- fides/api/alembic/migrations/versions/4bfbeff34611_add_polling_status.py +35 -0
- fides/api/alembic/migrations/versions/7db29f9cd77b_create_new_sub_request_table.py +95 -0
- fides/api/alembic/migrations/versions/9caf76161e55_make_user_assigned_data_uses_nullable_.py +64 -0
- fides/api/alembic/migrations/versions/b97e92b038d2_add_digest_execution_model.py +117 -0
- fides/api/alembic/migrations/versions/f108fa05c579_adds_optional_duration_field_to_assets.py +28 -0
- fides/api/api/v1/endpoints/generic_overrides.py +3 -9
- fides/api/common_exceptions.py +4 -0
- fides/api/main.py +2 -2
- fides/api/models/asset.py +14 -1
- fides/api/models/attachment.py +1 -0
- fides/api/models/detection_discovery/core.py +57 -3
- fides/api/models/digest/__init__.py +2 -0
- fides/api/models/digest/digest_config.py +10 -1
- fides/api/models/digest/digest_execution.py +132 -0
- fides/api/models/event_audit.py +8 -0
- fides/api/models/privacy_experience.py +10 -0
- fides/api/models/privacy_notice.py +131 -20
- fides/api/models/privacy_request/request_task.py +98 -1
- fides/api/models/worker_task.py +8 -0
- fides/api/schemas/saas/async_polling_configuration.py +81 -0
- fides/api/schemas/saas/saas_config.py +10 -3
- fides/api/schemas/saas/strategy_configuration.py +0 -12
- fides/api/service/async_dsr/handlers/__init__.py +0 -0
- fides/api/service/async_dsr/handlers/polling_attachment_handler.py +155 -0
- fides/api/service/async_dsr/handlers/polling_request_handler.py +88 -0
- fides/api/service/async_dsr/handlers/polling_response_handler.py +261 -0
- fides/api/service/async_dsr/handlers/polling_sub_request_handler.py +123 -0
- fides/api/service/async_dsr/strategies/__init__.py +0 -0
- fides/api/service/async_dsr/strategies/async_dsr_strategy.py +52 -0
- fides/api/service/async_dsr/strategies/async_dsr_strategy_callback.py +199 -0
- fides/api/service/async_dsr/strategies/async_dsr_strategy_factory.py +72 -0
- fides/api/service/async_dsr/strategies/async_dsr_strategy_polling.py +678 -0
- fides/api/service/async_dsr/utils.py +130 -0
- fides/api/service/connectors/fides/fides_client.py +63 -1
- fides/api/service/connectors/query_configs/saas_query_config.py +4 -5
- fides/api/service/connectors/saas_connector.py +77 -69
- fides/api/service/privacy_request/attachment_handling.py +9 -2
- fides/api/service/privacy_request/request_runner_service.py +9 -83
- fides/api/service/privacy_request/request_service.py +47 -74
- fides/api/service/saas_request/saas_request_override_factory.py +66 -1
- fides/api/task/execute_request_tasks.py +5 -2
- fides/api/task/filter_results.py +35 -2
- fides/api/task/graph_task.py +34 -2
- fides/config/execution_settings.py +7 -3
- fides/service/dataset/dataset_service.py +0 -39
- fides/service/privacy_request/privacy_request_service.py +48 -103
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/155-c1ae010c664e2245.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1817-1ad037b7d6d2f6d2.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3585-f728d32fda6f1ac1.js → 3585-efd5d41f08e180c4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/5279-12c9cbdc67ad7b14.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6277-182efc294d413f64.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7079-bbc7b856802a4834.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-75e99306393938e8.js → manual-4ec03eed67572861.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-fd41ffaff543e05a.js → [id]-e1e2fd704ac2d71d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{new-e74cb5ea87f15b40.js → new-a5e738a234dadc7e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-9c23fbe813c997d0.js → [id]-5fc78b78a51c239c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-0e5e38bbcfe59fd2.js → new-b79bcb93b5f4c734.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-29c1fb777bd464e0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-153eb88ab4e7dc6d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-f682b1def859931e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-febf156d2977f3ac.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-4d658222ec800511.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-547c6ef0ad52b85d.js → [id]-4d470bbf199a2f9c.js} +1 -1
- fides/ui-build/static/admin/_next/static/css/f38242c11f7fea64.css +1 -0
- fides/ui-build/static/admin/_next/static/vSOB67a-1uIVzRUKBYMSo/_buildManifest.js +1 -0
- fides/ui-build/static/admin/add-systems/manual.html +1 -1
- fides/ui-build/static/admin/add-systems/multiple.html +1 -1
- fides/ui-build/static/admin/add-systems.html +1 -1
- fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
- fides/ui-build/static/admin/consent/configure.html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
- fides/ui-build/static/admin/consent/properties.html +1 -1
- fides/ui-build/static/admin/consent/reporting.html +1 -1
- fides/ui-build/static/admin/consent.html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
- fides/ui-build/static/admin/data-catalog.html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
- fides/ui-build/static/admin/data-discovery/activity.html +1 -1
- fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-discovery/detection.html +1 -1
- fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
- fides/ui-build/static/admin/datamap.html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
- fides/ui-build/static/admin/dataset/new.html +1 -1
- fides/ui-build/static/admin/dataset.html +1 -1
- fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
- fides/ui-build/static/admin/datastore-connection/new.html +1 -1
- fides/ui-build/static/admin/datastore-connection.html +1 -1
- fides/ui-build/static/admin/index.html +1 -1
- fides/ui-build/static/admin/integrations/[id].html +1 -1
- fides/ui-build/static/admin/integrations.html +1 -1
- fides/ui-build/static/admin/lib/fides-headless.js +1 -1
- fides/ui-build/static/admin/lib/fides-preview.js +1 -1
- fides/ui-build/static/admin/lib/fides-tcf.js +3 -3
- fides/ui-build/static/admin/lib/fides.js +3 -3
- fides/ui-build/static/admin/login/[provider].html +1 -1
- fides/ui-build/static/admin/login.html +1 -1
- fides/ui-build/static/admin/messaging/[id].html +1 -1
- fides/ui-build/static/admin/messaging/add-template.html +1 -1
- fides/ui-build/static/admin/messaging.html +1 -1
- fides/ui-build/static/admin/poc/ant-components.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
- fides/ui-build/static/admin/poc/forms.html +1 -1
- fides/ui-build/static/admin/poc/table-migration.html +1 -1
- fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
- fides/ui-build/static/admin/privacy-requests.html +1 -1
- fides/ui-build/static/admin/properties/[id].html +1 -1
- fides/ui-build/static/admin/properties/add-property.html +1 -1
- fides/ui-build/static/admin/properties.html +1 -1
- fides/ui-build/static/admin/reporting/datamap.html +1 -1
- fides/ui-build/static/admin/settings/about/alpha.html +1 -1
- fides/ui-build/static/admin/settings/about.html +1 -1
- fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
- fides/ui-build/static/admin/settings/consent.html +1 -1
- fides/ui-build/static/admin/settings/custom-fields/[id].html +1 -1
- fides/ui-build/static/admin/settings/custom-fields/new.html +1 -1
- fides/ui-build/static/admin/settings/custom-fields.html +1 -1
- fides/ui-build/static/admin/settings/domain-records.html +1 -1
- fides/ui-build/static/admin/settings/domains.html +1 -1
- fides/ui-build/static/admin/settings/email-templates.html +1 -1
- fides/ui-build/static/admin/settings/locations.html +1 -1
- fides/ui-build/static/admin/settings/messaging-providers/[key].html +1 -1
- fides/ui-build/static/admin/settings/messaging-providers/new.html +1 -1
- fides/ui-build/static/admin/settings/messaging-providers.html +1 -1
- fides/ui-build/static/admin/settings/organization.html +1 -1
- fides/ui-build/static/admin/settings/privacy-requests.html +1 -1
- fides/ui-build/static/admin/settings/regulations.html +1 -1
- fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
- fides/ui-build/static/admin/systems/configure/[id].html +1 -1
- fides/ui-build/static/admin/systems.html +1 -1
- fides/ui-build/static/admin/taxonomy.html +1 -1
- fides/ui-build/static/admin/user-management/new.html +1 -1
- fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
- fides/ui-build/static/admin/user-management.html +1 -1
- fides/api/service/async_dsr/async_dsr_service.py +0 -195
- fides/api/service/async_dsr/async_dsr_strategy.py +0 -5
- fides/api/service/async_dsr/async_dsr_strategy_callback.py +0 -16
- fides/api/service/async_dsr/async_dsr_strategy_factory.py +0 -63
- fides/api/service/async_dsr/async_dsr_strategy_polling.py +0 -94
- fides/ui-build/static/admin/_next/static/IPOgh7BMBX7b_r8-scpgv/_buildManifest.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/155-047c3806cc41295e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1817-ca6473f31a67a804.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3700-08e0703b1ef770da.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6084-d0943ee628bf4388.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6416-0ccadfefcdad00cc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-2e1e2b7808d3b21f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-01e025f878ba806c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-14120a529d7dac27.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-7dac2302f573f5ee.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-e5d781b28f8e29c8.js +0 -1
- fides/ui-build/static/admin/_next/static/css/073713cd1eddda79.css +0 -1
- {ethyca_fides-2.71.1b0.dist-info → ethyca_fides-2.71.1rc0.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.71.1b0.dist-info → ethyca_fides-2.71.1rc0.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.71.1b0.dist-info → ethyca_fides-2.71.1rc0.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.71.1b0.dist-info → ethyca_fides-2.71.1rc0.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{_app-a77584f9ad3334af.js → _app-a7c02dd2ff07f9e1.js} +0 -0
- /fides/ui-build/static/admin/_next/static/{IPOgh7BMBX7b_r8-scpgv → vSOB67a-1uIVzRUKBYMSo}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
from typing import Any, Dict, List
|
|
2
|
+
|
|
3
|
+
from loguru import logger
|
|
4
|
+
from sqlalchemy.orm import Session
|
|
5
|
+
|
|
6
|
+
from fides.api.common_exceptions import AwaitingAsyncTask
|
|
7
|
+
from fides.api.models.privacy_request.request_task import AsyncTaskType, RequestTask
|
|
8
|
+
from fides.api.service.async_dsr.strategies.async_dsr_strategy import AsyncDSRStrategy
|
|
9
|
+
from fides.api.service.async_dsr.utils import AsyncPhase, get_async_phase
|
|
10
|
+
from fides.api.service.connectors.query_configs.saas_query_config import SaaSQueryConfig
|
|
11
|
+
from fides.api.service.connectors.saas.authenticated_client import AuthenticatedClient
|
|
12
|
+
from fides.api.util.collection_util import Row
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class AsyncCallbackStrategy(AsyncDSRStrategy):
|
|
16
|
+
"""
|
|
17
|
+
Enhanced strategy for callback async DSR requests.
|
|
18
|
+
Works for both access and erasure operations with internal phase-based organization.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
type = AsyncTaskType.callback
|
|
22
|
+
|
|
23
|
+
def __init__(self, session: Session):
|
|
24
|
+
self.session = session
|
|
25
|
+
|
|
26
|
+
def async_retrieve_data(
|
|
27
|
+
self,
|
|
28
|
+
client: AuthenticatedClient,
|
|
29
|
+
request_task_id: str,
|
|
30
|
+
query_config: SaaSQueryConfig,
|
|
31
|
+
input_data: Dict[str, List[Any]],
|
|
32
|
+
) -> List[Row]:
|
|
33
|
+
"""Execute async retrieve data with internal phase routing."""
|
|
34
|
+
request_task = self._get_request_task(request_task_id)
|
|
35
|
+
async_phase = get_async_phase(request_task, query_config)
|
|
36
|
+
|
|
37
|
+
if async_phase == AsyncPhase.initial_async:
|
|
38
|
+
return self._initial_request_access(
|
|
39
|
+
client, request_task, query_config, input_data
|
|
40
|
+
)
|
|
41
|
+
if async_phase == AsyncPhase.callback_completion:
|
|
42
|
+
return self._callback_completion_access(request_task)
|
|
43
|
+
|
|
44
|
+
logger.warning(
|
|
45
|
+
f"Unexpected async phase '{async_phase}' for callback access task {request_task.id}"
|
|
46
|
+
)
|
|
47
|
+
return []
|
|
48
|
+
|
|
49
|
+
def async_mask_data(
|
|
50
|
+
self,
|
|
51
|
+
client: AuthenticatedClient,
|
|
52
|
+
request_task_id: str,
|
|
53
|
+
query_config: SaaSQueryConfig,
|
|
54
|
+
rows: List[Row],
|
|
55
|
+
) -> int:
|
|
56
|
+
"""Execute async mask data with internal phase routing."""
|
|
57
|
+
request_task = self._get_request_task(request_task_id)
|
|
58
|
+
async_phase = get_async_phase(request_task, query_config)
|
|
59
|
+
|
|
60
|
+
if async_phase == AsyncPhase.initial_async:
|
|
61
|
+
return self._initial_request_erasure(
|
|
62
|
+
client, request_task, query_config, rows
|
|
63
|
+
)
|
|
64
|
+
if async_phase == AsyncPhase.callback_completion:
|
|
65
|
+
return self._callback_completion_erasure(request_task)
|
|
66
|
+
|
|
67
|
+
logger.warning(
|
|
68
|
+
f"Unexpected async phase '{async_phase}' for callback erasure task {request_task.id}"
|
|
69
|
+
)
|
|
70
|
+
return 0
|
|
71
|
+
|
|
72
|
+
# Private helper methods
|
|
73
|
+
|
|
74
|
+
def _initial_request_access(
|
|
75
|
+
self,
|
|
76
|
+
client: AuthenticatedClient,
|
|
77
|
+
request_task: RequestTask,
|
|
78
|
+
query_config: SaaSQueryConfig,
|
|
79
|
+
input_data: Dict[str, List[Any]],
|
|
80
|
+
) -> List[Row]:
|
|
81
|
+
"""Handle initial setup for access callback requests."""
|
|
82
|
+
logger.info(f"Initial callback request for access task {request_task.id}")
|
|
83
|
+
|
|
84
|
+
read_requests = query_config.get_read_requests_by_identity()
|
|
85
|
+
|
|
86
|
+
# Filter to get only the requests that need async processing
|
|
87
|
+
async_requests_to_process = [
|
|
88
|
+
req for req in read_requests if req.async_config and request_task.id
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
# If there are no async requests, we shouldn't be in this handler.
|
|
92
|
+
if not async_requests_to_process:
|
|
93
|
+
logger.warning(
|
|
94
|
+
f"Async callback handler was called, but no async-configured read requests were found for task {request_task.id}."
|
|
95
|
+
)
|
|
96
|
+
return []
|
|
97
|
+
|
|
98
|
+
# Set async_type once for the request task
|
|
99
|
+
request_task.async_type = AsyncTaskType.callback
|
|
100
|
+
self.session.commit()
|
|
101
|
+
|
|
102
|
+
# For callback strategy, we execute the initial request to trigger the callback
|
|
103
|
+
# then wait for the external system to call us back via webhook.
|
|
104
|
+
# The callback endpoint logic will then queue the request task for it
|
|
105
|
+
# to be executed again with
|
|
106
|
+
# AsyncCallbackStrategy.async_retrieve_data -> _callback_completion_access
|
|
107
|
+
|
|
108
|
+
# Execute the initial callback request to trigger the async process
|
|
109
|
+
privacy_request = request_task.privacy_request
|
|
110
|
+
policy = privacy_request.policy
|
|
111
|
+
|
|
112
|
+
for read_request in async_requests_to_process:
|
|
113
|
+
if read_request.path: # Only execute if there's an actual request to make
|
|
114
|
+
try:
|
|
115
|
+
# Set the current request context
|
|
116
|
+
query_config.current_request = read_request
|
|
117
|
+
prepared_request = query_config.generate_query(input_data, policy)
|
|
118
|
+
# Execute the initial request to trigger the callback
|
|
119
|
+
client.send(prepared_request, read_request.ignore_errors)
|
|
120
|
+
logger.info(
|
|
121
|
+
f"Executed initial callback request for access task {request_task.id}"
|
|
122
|
+
)
|
|
123
|
+
except ValueError as exc:
|
|
124
|
+
if read_request.skip_missing_param_values:
|
|
125
|
+
logger.debug(
|
|
126
|
+
"Skipping optional access callback request: {}",
|
|
127
|
+
exc,
|
|
128
|
+
)
|
|
129
|
+
continue
|
|
130
|
+
raise exc
|
|
131
|
+
|
|
132
|
+
# Asynchronous callback access request detected in saas config.
|
|
133
|
+
# We raise AwaitingAsyncTask to put this task in an awaiting_processing state.
|
|
134
|
+
raise AwaitingAsyncTask(
|
|
135
|
+
f"Awaiting callback from {request_task.dataset_name} for access results"
|
|
136
|
+
)
|
|
137
|
+
|
|
138
|
+
def _initial_request_erasure(
|
|
139
|
+
self,
|
|
140
|
+
client: AuthenticatedClient,
|
|
141
|
+
request_task: RequestTask,
|
|
142
|
+
query_config: SaaSQueryConfig,
|
|
143
|
+
rows: List[Row],
|
|
144
|
+
) -> int:
|
|
145
|
+
"""Handle initial setup for erasure callback requests."""
|
|
146
|
+
logger.info(f"Initial callback request for erasure task {request_task.id}")
|
|
147
|
+
|
|
148
|
+
privacy_request = request_task.privacy_request
|
|
149
|
+
policy = privacy_request.policy
|
|
150
|
+
|
|
151
|
+
# For erasure, we only execute masking requests (delete/update requests)
|
|
152
|
+
masking_request = query_config.get_masking_request()
|
|
153
|
+
|
|
154
|
+
if not masking_request:
|
|
155
|
+
logger.warning(
|
|
156
|
+
f"No masking request found for erasure task {request_task.id}"
|
|
157
|
+
)
|
|
158
|
+
return 0
|
|
159
|
+
|
|
160
|
+
rows_updated = 0
|
|
161
|
+
|
|
162
|
+
# Check if the masking request has async_config and set async_type once
|
|
163
|
+
if masking_request.async_config and request_task.id:
|
|
164
|
+
request_task.async_type = AsyncTaskType.callback
|
|
165
|
+
self.session.commit()
|
|
166
|
+
|
|
167
|
+
if masking_request.path:
|
|
168
|
+
for row in rows:
|
|
169
|
+
try:
|
|
170
|
+
prepared_request = query_config.generate_update_stmt(
|
|
171
|
+
row, policy, privacy_request
|
|
172
|
+
)
|
|
173
|
+
client.send(prepared_request, masking_request.ignore_errors)
|
|
174
|
+
rows_updated += 1
|
|
175
|
+
except ValueError as exc:
|
|
176
|
+
if masking_request.skip_missing_param_values:
|
|
177
|
+
logger.debug(
|
|
178
|
+
"Skipping optional masking request: {}",
|
|
179
|
+
exc,
|
|
180
|
+
)
|
|
181
|
+
continue
|
|
182
|
+
raise exc
|
|
183
|
+
|
|
184
|
+
raise AwaitingAsyncTask("Awaiting erasure callback results")
|
|
185
|
+
|
|
186
|
+
logger.warning(
|
|
187
|
+
f"No async configuration found for erasure task {request_task.id}"
|
|
188
|
+
)
|
|
189
|
+
return rows_updated
|
|
190
|
+
|
|
191
|
+
def _callback_completion_access(self, request_task: RequestTask) -> List[Row]:
|
|
192
|
+
"""Handle completion of access callback requests."""
|
|
193
|
+
logger.info(f"Access callback succeeded for request task '{request_task.id}'")
|
|
194
|
+
return request_task.get_access_data()
|
|
195
|
+
|
|
196
|
+
def _callback_completion_erasure(self, request_task: RequestTask) -> int:
|
|
197
|
+
"""Handle completion of erasure callback requests."""
|
|
198
|
+
logger.info(f"Masking callback succeeded for request task '{request_task.id}'")
|
|
199
|
+
return request_task.rows_masked or 0
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
from typing import Any, Dict, List, Optional
|
|
3
|
+
|
|
4
|
+
from pydantic import ValidationError
|
|
5
|
+
from sqlalchemy.orm import Session
|
|
6
|
+
|
|
7
|
+
from fides.api.common_exceptions import NoSuchStrategyException
|
|
8
|
+
from fides.api.common_exceptions import ValidationError as FidesopsValidationError
|
|
9
|
+
from fides.api.schemas.saas.async_polling_configuration import AsyncPollingConfiguration
|
|
10
|
+
from fides.api.service.async_dsr.strategies.async_dsr_strategy import AsyncDSRStrategy
|
|
11
|
+
from fides.api.service.async_dsr.strategies.async_dsr_strategy_callback import (
|
|
12
|
+
AsyncCallbackStrategy,
|
|
13
|
+
)
|
|
14
|
+
from fides.api.service.async_dsr.strategies.async_dsr_strategy_polling import (
|
|
15
|
+
AsyncPollingStrategy,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class SupportedAsyncDSRStrategies(Enum):
|
|
20
|
+
"""
|
|
21
|
+
The supported async DSR strategies for handling asynchronous data subject requests.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
callback = AsyncCallbackStrategy
|
|
25
|
+
polling = AsyncPollingStrategy
|
|
26
|
+
|
|
27
|
+
@classmethod
|
|
28
|
+
def __contains__(cls, item: str) -> bool:
|
|
29
|
+
try:
|
|
30
|
+
cls[item]
|
|
31
|
+
except KeyError:
|
|
32
|
+
return False
|
|
33
|
+
|
|
34
|
+
return True
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def get_strategy(
|
|
38
|
+
strategy_name: str,
|
|
39
|
+
session: Session,
|
|
40
|
+
configuration: Optional[Dict[str, Any]] = None,
|
|
41
|
+
) -> AsyncDSRStrategy:
|
|
42
|
+
"""
|
|
43
|
+
Returns the enhanced strategy given the name, session, and configuration.
|
|
44
|
+
Raises NoSuchStrategyException if the strategy does not exist
|
|
45
|
+
"""
|
|
46
|
+
if not SupportedAsyncDSRStrategies.__contains__(strategy_name):
|
|
47
|
+
valid_strategies = ", ".join(get_strategy_names())
|
|
48
|
+
raise NoSuchStrategyException(
|
|
49
|
+
f"Strategy '{strategy_name}' does not exist. Valid strategies are [{valid_strategies}]"
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
strategy_class = SupportedAsyncDSRStrategies[strategy_name].value
|
|
53
|
+
|
|
54
|
+
if strategy_name == "polling":
|
|
55
|
+
# Polling strategy requires configuration
|
|
56
|
+
if not configuration:
|
|
57
|
+
raise FidesopsValidationError("Configuration required for polling strategy")
|
|
58
|
+
try:
|
|
59
|
+
strategy_config = AsyncPollingConfiguration(**configuration)
|
|
60
|
+
return strategy_class(session, strategy_config)
|
|
61
|
+
except ValidationError as e:
|
|
62
|
+
raise FidesopsValidationError(message=str(e))
|
|
63
|
+
elif strategy_name == "callback":
|
|
64
|
+
# Callback strategy only requires session
|
|
65
|
+
return strategy_class(session)
|
|
66
|
+
|
|
67
|
+
raise NoSuchStrategyException(f"Unsupported strategy: {strategy_name}")
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_strategy_names() -> List[str]:
|
|
71
|
+
"""Returns all supported async DSR strategies"""
|
|
72
|
+
return [s.name for s in SupportedAsyncDSRStrategies]
|