ethyca-fides 2.71.1b1__py2.py3-none-any.whl → 2.74.0rc1__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.1b1.dist-info → ethyca_fides-2.74.0rc1.dist-info}/METADATA +3 -2
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.74.0rc1.dist-info}/RECORD +377 -327
- fides/_version.py +3 -3
- fides/api/alembic/alembic.ini +5 -1
- fides/api/alembic/migrations/env.py +7 -1
- fides/api/alembic/migrations/versions/4bfbeff34611_add_polling_status.py +68 -0
- fides/api/alembic/migrations/versions/65a1bc82ae09_adds_experience_config_for_delete_.py +53 -0
- fides/api/alembic/migrations/versions/7db29f9cd77b_create_new_sub_request_table.py +95 -0
- fides/api/alembic/migrations/versions/a55e12c2c2df_add_tagging_instructions_to_data_.py +29 -0
- fides/api/alembic/migrations/versions/b97e92b038d2_add_digest_execution_model.py +117 -0
- fides/api/alembic/migrations/versions/c09e76282dd1_add_privacy_request_duplication_cols.py +64 -0
- fides/api/alembic/migrations/versions/xx_2025_10_17_1603_5093e92e2a5a_add_consent_data_v3_to_the_database.py +72 -0
- fides/api/alembic/migrations/versions/xx_2025_10_27_1834_67f0f2f4748e_adding_identity_definition_model.py +45 -0
- fides/api/alembic/migrations/versions/xx_2025_10_29_1659_80d28dea3b6b_added_duplicate_group_table.py +79 -0
- fides/api/alembic/migrations/versions/xx_2025_11_05_0200_f1a2b3c4d5e6_create_staged_resource_error_table.py +82 -0
- fides/api/api/v1/endpoints/connection_endpoints.py +38 -45
- fides/api/api/v1/endpoints/generic_overrides.py +75 -6
- fides/api/api/v1/endpoints/privacy_request_endpoints.py +60 -6
- fides/api/api/v1/endpoints/saas_config_endpoints.py +60 -48
- fides/api/api/v1/endpoints/system.py +11 -43
- fides/api/api/v1/endpoints/user_endpoints.py +8 -1
- fides/api/app_setup.py +1 -3
- fides/api/common_exceptions.py +8 -0
- fides/api/db/base.py +2 -0
- fides/api/db/database.py +257 -2
- fides/api/email_templates/get_email_template.py +3 -0
- fides/api/email_templates/template_names.py +1 -0
- fides/api/email_templates/templates/manual_task_digest.html +316 -0
- fides/api/main.py +2 -2
- fides/api/models/attachment.py +1 -0
- fides/api/models/detection_discovery/__init__.py +2 -0
- fides/api/models/detection_discovery/core.py +10 -0
- fides/api/models/detection_discovery/monitor_task.py +1 -0
- fides/api/models/detection_discovery/staged_resource_error.py +25 -0
- fides/api/models/digest/__init__.py +2 -0
- fides/api/models/digest/digest_config.py +10 -1
- fides/api/models/digest/digest_execution.py +142 -0
- fides/api/models/event_audit.py +17 -0
- fides/api/models/identity_definition.py +65 -0
- fides/api/models/messaging_template.py +7 -0
- fides/api/models/privacy_experience.py +11 -0
- fides/api/models/privacy_preference.py +2 -0
- fides/api/models/privacy_request/duplicate_group.py +84 -0
- fides/api/models/privacy_request/privacy_request.py +56 -8
- fides/api/models/privacy_request/request_task.py +98 -1
- fides/api/models/sql_models.py +3 -0
- fides/api/models/taxonomy.py +14 -4
- fides/api/models/v3/__init__.py +0 -0
- fides/api/models/v3/privacy_preferences.py +85 -0
- fides/api/models/worker_task.py +8 -0
- fides/api/schemas/application_config.py +28 -0
- fides/api/schemas/connection_configuration/connection_config.py +1 -30
- fides/api/schemas/messaging/messaging.py +15 -0
- fides/api/schemas/privacy_request.py +17 -3
- 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/schemas/taxonomy_extensions.py +8 -0
- 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 +686 -0
- fides/api/service/async_dsr/utils.py +130 -0
- fides/api/service/connectors/bigquery_connector.py +34 -16
- fides/api/service/connectors/fides/fides_client.py +63 -1
- fides/api/service/connectors/query_configs/saas_query_config.py +160 -79
- fides/api/service/connectors/saas/connector_registry_service.py +1 -138
- fides/api/service/connectors/saas_connector.py +116 -94
- fides/api/service/connectors/sql_connector.py +14 -4
- fides/api/service/deps.py +8 -0
- fides/api/service/messaging/message_dispatch_service.py +38 -1
- fides/api/service/privacy_request/attachment_handling.py +9 -2
- fides/api/service/privacy_request/duplication_detection.py +424 -0
- fides/api/service/privacy_request/request_runner_service.py +46 -84
- fides/api/service/privacy_request/request_service.py +47 -74
- fides/api/service/saas_request/saas_request_override_factory.py +71 -1
- fides/api/task/execute_request_tasks.py +17 -9
- fides/api/task/filter_results.py +35 -2
- fides/api/task/graph_task.py +37 -8
- fides/api/tasks/__init__.py +0 -1
- fides/api/util/connection_util.py +99 -215
- fides/api/util/event_audit_util.py +230 -0
- fides/api/util/logger_context_utils.py +3 -1
- fides/api/util/masking_util.py +31 -0
- fides/api/util/memory_watchdog.py +118 -0
- fides/api/util/saas_config_updater.py +66 -0
- fides/api/util/saas_util.py +28 -1
- fides/common/api/scope_registry.py +0 -7
- fides/common/api/v1/urn_registry.py +2 -0
- fides/config/__init__.py +10 -1
- fides/config/celery_settings.py +42 -0
- fides/config/config_proxy.py +10 -0
- fides/config/duplicate_detection_settings.py +31 -0
- fides/config/execution_settings.py +7 -3
- fides/config/utils.py +5 -0
- fides/data/language/languages.yml +2 -0
- fides/service/connection/__init__.py +0 -0
- fides/service/connection/connection_service.py +651 -0
- fides/service/event_audit_service.py +16 -22
- fides/service/privacy_request/privacy_request_service.py +162 -43
- fides/service/taxonomy/handlers/legacy_handler.py +3 -3
- fides/service/taxonomy/taxonomy_service.py +15 -15
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/FZTEUgamBvOhgPWce135w/_buildManifest.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{1115-90baef2a89f361ad.js → 1115-0da062111df309bf.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6148-59a59d5c5925344f.js → 1533-84e250d1f26e6d7d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/1817-508b16628e8eb225.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1840-5bbe6d878ed73fb4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{1975.78e719130cfe3fd6.js → 1975.afe8cad52f904fcf.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{2040-fdecc41a18e40bdc.js → 2040-fe1a06d82c0413f1.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/2397-40b8db1cb2f23e2a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/2921-b10bbc3a9104933b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3214-90ce0a366b0f461a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3377-eb5cd82b3ee6ab0c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3615-5e2d062d684b8fa1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3655-93ecd09f1cb9dbef.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3696-90c8b336bbc46782.js → 3696-6db05a35ae806825.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{3923-98bea73b618292aa.js → 3923-44255a63d6d80ff5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/401-fe8db8b5d8f600de.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{4259.d1507e0db19cbed7.js → 4259.05038c9b78467244.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/4277-13bcf4516326d474.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/431-e01ee730c8ad9ece.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4496-bed72bd5639075be.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/454-d5c2c84f1a14e4f1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4817-d29f40d4ce729f37.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5185-b2ac9fecc00b67e7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5258-4672eae0656430f9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5487-8dedd1ca94fbba54.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/549-6e2442db533a711e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5643-55d758444a8d7162.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5724-1e40975cefa405f0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{5783-d119cb132abd8a91.js → 5783-6055edba275155ca.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/6084-82e2df433fe5ba85.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6344-3e21444374f8059f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6362-12e3fd23130ccf15.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6372-a8d0f08dac1ebd0e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6780-3db5133c1f4c6f1e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6853-1adbdf6418ec3d62.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6954-aa0c60ee1092be8e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7059-12be23a345a94c1e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7079-6e6efc3396ff1ebb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7218-d297a4a06f924b09.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7245-686665c197b58e68.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{7476-d055aa931da47ac0.js → 7476-a43c046c24de37cc.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/7630-c654c61ba98d8c74.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7654-716cf37a020b3d11.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{796-02086581996a0548.js → 796-e83ace3c6ab99ac7.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/8212-b9e8295ca883c9f8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/8939-4925751c57c51f87.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9014-eeae6f581158e645.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9046-e4daf28840a69fd6.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{5596-29a7c8322530b7cf.js → 9195-550bd50d538c5f79.js} +3 -3
- fides/ui-build/static/admin/_next/static/chunks/9330-e519adec48222d45.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9341-bfc0e59bcc56c604.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9450-b7b7bb1d755ecf57.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{9676.b86ecbcfe5afd25d.js → 9676.7d029a5383595b69.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9682-da69ac5d06f281da.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{9826-ccedc28e978ca9e1.js → 9826-657652d55936a8c6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9911-ece086f2230e34f0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9965-56c5e4fc9cd3b3a5.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{404-2eb8aed4939f1142.js → 404-d079b8bf35250874.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-c1c2f757b1f3da12.js → _app-e64fd8510033a27c.js} +63 -63
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-ddd9d7d40847fc28.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/multiple-b4d18c1f4d414f5f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-d451bc8932330141.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-7a258b7ecd6da4b8.js → add-vendors-c24663cd5dec57db.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-fb5017ff5fa54fcc.js → configure-d93418688bd258eb.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-e1e2fd704ac2d71d.js → [id]-9b1f2b1c06968166.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{new-a5e738a234dadc7e.js → new-115a085e5d42de45.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-d9b7b311195df29e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-5fc78b78a51c239c.js → [id]-3de34624829cbce8.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-b79bcb93b5f4c734.js → new-dc95e7ed278d1a29.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-cdfc9bb19f47c709.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-069f4e3ee96ebf77.js → properties-0b995b01dc4dbd1f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-e3ad3a55624e302a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{consent-d2bf72508c3cad55.js → consent-b37ed76849330edd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-2fa4b3a58f75f81d.js → [resourceUrn]-dd82729296dee5c5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-49e5477eb1a11b92.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-dfc1ead4a12c9ffa.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-5b31e3d7727b917a.js → [resourceUrn]-8442eb219958ac7e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources-feda358d1801c18d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-d16acb6fc07aad46.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/datastore/[monitorId]-c51a1e98c45d231a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/datastore-4498881c26f1458d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/website/[monitorId]/[systemId]-bcfe38eebca30f8c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/website/[monitorId]-f66d0655897c4400.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/website-5b3e0009d442bc3f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-6f1e012cd641da19.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-581d6248fcf98d17.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-844a8de0d1b506e2.js → [resourceUrn]-ddc1c1641e1e9430.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-11b07cf2d91b17ef.js → detection-2b48f7e524743b2b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-5525cf287d4ab493.js → [resourceUrn]-862b67418600251e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-ed4723e1b67d890e.js → discovery-0ffec855f5df262c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datamap-6a030ab8c2e2b0db.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-6cb66f649b8ca4bf.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-0b008dad90b00aaa.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-5566edf9a9d1be2d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-d4ca1f485b6e9e02.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-85dee7e81dc4bafb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-e905e018a2cab35d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-912723bc86299b1a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-f1f0affc18327033.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{fides-js-docs-1f4335dca5c09860.js → fides-js-docs-5235760b3e508d7d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{index-b74d1e8608ae5b5d.js → index-692d27dbe9392c9f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-1b94e2d769a182b2.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-adfe6c5ac5b703d0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/new-privacy-requests-f9be7080ebbb7445.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/digests/[id]-caaa8602a1d449b1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/digests/new-9b106b1d2d93985b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/digests-6a1ded8cdde836c4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/providers/[key]-f94e3accf9507ebf.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/providers/new-5e83220ff1f2a250.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/providers-a03cbd698a23e5b3.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/templates/[id]-3cde574b3c8447c0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/templates/add-template-0448bb4ae8536c58.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications/templates-1621a4b87c432117.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/notifications-4ea28f6b1dd63642.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-e02516d9fd314528.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/AntForm-fec08bea801b4918.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikAntFormItem-d911e5fbf5a4a888.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikControlled-91b1adcac6a57b2d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikField-de309d8813b1ebfb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/forms-f2943c1309062284.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/{table-migration-29fb7b39f8962650.js → table-migration-03eda417711ae909.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-1fe486f3af832c80.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-ea6f78fa8b2d3f6c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-8f577df28ebca869.js → configure-bda7b474493e7128.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-2c0ec8fed16c20ae.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-57a75c7e9659271a.js → [id]-30d298a47e85709f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-8964c2300206bc89.js → add-property-438084cca0d0f10d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{properties-08472b2a6bf1d392.js → properties-17fd44d98f5bd5b6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-baf77d34a3b3bece.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/sandbox/privacy-notices-8c80391025ca7339.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-7c19810858b708cc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-ee8820fe0fa14c77.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields/{[id]-bd1042a0e9be6aff.js → [id]-8eb862182f19a6c2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields/{new-469ad83c8cfa1290.js → new-37c29ef618e9fe3c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-1db425150dcb1b6b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-744f669431b84f71.js → domain-records-e334b43fa5c5b1e6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-9d18eb5c38d85522.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-604790638c656fbd.js → email-templates-cb937ed7c4b1e5a8.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-be2a885150adc133.js → locations-835281251f0785cd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-3c86162afe9759df.js → organization-7fd050c92866938c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/privacy-requests-59ea66130fca0d05.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-4fe3b90747d885e5.js → regulations-b0fe1051d908f366.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-f108bf5015144d2f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-4d470bbf199a2f9c.js → [id]-0e7c7228d01290ea.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-adc13b542e10a37d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-23dd250da26511c5.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-98f737e735eaa0f0.js → [id]-aed30fb22ae7c9ec.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-562624e5461083ec.js → user-management-6b88ca3e02ee67c9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/webpack-6f97ebe373e7ef6b.js +1 -0
- fides/ui-build/static/admin/_next/static/css/012b10627a654d5c.css +1 -0
- fides/ui-build/static/admin/_next/static/css/05d05fc31d09638b.css +1 -0
- fides/ui-build/static/admin/_next/static/css/0fd6e0884cfcc5f3.css +1 -0
- fides/ui-build/static/admin/_next/static/css/14ba79c49597d37a.css +1 -0
- fides/ui-build/static/admin/_next/static/css/{34a7eb08b86ddb57.css → 3d6582469f7d56e0.css} +1 -1
- fides/ui-build/static/admin/_next/static/css/4861ca3e088f2d05.css +1 -0
- fides/ui-build/static/admin/_next/static/css/65ae906f224cd8ae.css +1 -0
- fides/ui-build/static/admin/_next/static/css/a1800714b486e230.css +1 -0
- fides/ui-build/static/admin/_next/static/css/af32fcac7a177a0e.css +1 -0
- fides/ui-build/static/admin/_next/static/css/cb417f0587918f85.css +1 -0
- fides/ui-build/static/admin/_next/static/css/d5701118537cbdd2.css +1 -0
- fides/ui-build/static/admin/_next/static/css/dd15c278b964de80.css +1 -0
- fides/ui-build/static/admin/_next/static/css/{5f393dea1c0d031c.css → f89607996ad54f4b.css} +1 -1
- fides/ui-build/static/admin/_next/static/css/f9a2a44d3d34c904.css +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/datastore/[monitorId].html +1 -0
- fides/ui-build/static/admin/data-discovery/action-center/datastore.html +1 -0
- fides/ui-build/static/admin/data-discovery/action-center/website/[monitorId]/[systemId].html +1 -0
- fides/ui-build/static/admin/data-discovery/action-center/website/[monitorId].html +1 -0
- fides/ui-build/static/admin/data-discovery/action-center/website.html +1 -0
- 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-ext-gpp.js +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/new-privacy-requests.html +1 -0
- fides/ui-build/static/admin/notifications/digests/[id].html +1 -0
- fides/ui-build/static/admin/notifications/digests/new.html +1 -0
- fides/ui-build/static/admin/notifications/digests.html +1 -0
- fides/ui-build/static/admin/notifications/providers/[key].html +1 -0
- fides/ui-build/static/admin/notifications/providers/new.html +1 -0
- fides/ui-build/static/admin/notifications/providers.html +1 -0
- fides/ui-build/static/admin/notifications/templates/[id].html +1 -0
- fides/ui-build/static/admin/notifications/templates/add-template.html +1 -0
- fides/ui-build/static/admin/notifications/templates.html +1 -0
- fides/ui-build/static/admin/notifications.html +1 -0
- 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/sandbox/privacy-notices.html +1 -0
- 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/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/_IxwgneyQjdSaZFEF3Tqu/_buildManifest.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1316-2606e19807c08aa5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1467-8808ec8836e033f9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/155-b4337d0826d5addc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1817-1ad037b7d6d2f6d2.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1896-49010da5c2705fc5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/2150-930ffaf2c4718edc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/255-1bc0cbef7a59cdc6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/2921-66f65496c3a09316.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/2962-e92d525bf570a9a3.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/346-aa3b88efb85f2e28.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3550-83cb70e80cbe41ba.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3585-f728d32fda6f1ac1.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3855-ed226b8a8050bd40.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3872-04d3afbfa41a7782.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/401-ffe4e8436e1eceb9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/409-5c3d31163028339f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/431-78bf05f35d7eec4f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4558-8305aee48def1dcd.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4608-0c6ef78e30a51f84.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4718-3a412bdb90add82f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/502-0d9f4ac29ef34a1c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/504-88caa30c03374e9b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5163-e682273cd76a7d07.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5185-51eaa78e3ed6bfb7.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5279-12c9cbdc67ad7b14.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5309-3b6cf0cc9d0c6a83.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5574-c31ea831371610d5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5619-9b50cec521203989.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5643-10a36584c399526c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6277-182efc294d413f64.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6419-9b3a86af57c86791.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6853-7004a8c420b1ca02.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6882-dbe0a25dcf1a8ee0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6954-4b24e1731c1cc3b3.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/699-8ca44b0de9fa20f0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7045-14e955890f1147e4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7079-50571e9f3269d74d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7158-04745cc8d684b2e7.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7218-e2983b96b95e33b4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7630-d0d3a0fe3f95e971.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7725-f2a7be705b75dcc3.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7929-0fd0d4948bc8d70e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/8002-ed832921ad190832.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/8765-f622a35b40a7ec63.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9037-453224ba3ee65b13.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9046-b6616ba7b59d947e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9187-7438242f0d380bb0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9226-4a7027057f55ca2a.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9278-08cc704317fe535e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9729-fcf6ff4e3534e4a8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-4ec03eed67572861.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/multiple-2ca59996860a33c5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-19214babd1f219e3.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-92182be6603c2842.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-ab54b19609bff325.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-c1a3caf3c286bf5d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-4a1af12d2d7cd660.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-99573a1ee3ef8f4c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources-6e429b7511028d60.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-b7326c51d88cc2cc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-5b57f9132426fe52.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-0d512528b498d75c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-040813022f0890c9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-a28cc0e23bbe4fc8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datamap-7d22222608ec3aac.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-0abd30eada811b5b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-007965429368d9a3.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-60a4a9eb4aab4c11.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-d514cd4ec62e3b03.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-0e3a6ac4797ffbbb.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-816e02b6cbe4a684.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-b6838162200141b3.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-223c2d1ded51bfb1.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-153eb88ab4e7dc6d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-331544e9b85c4ac2.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/[id]-e8d2140787045acd.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/add-template-e3f93462a08251bf.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging-b5f7d6afdecd013d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-248ad9f65a872442.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/AntForm-aedb66a62042b10a.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikAntFormItem-018df38b7cd77fdb.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikControlled-6ca9099d03aab817.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikField-0f2c90786ea005a4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/forms-200b51a725f8b2d1.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/privacy-requests/configure/storage-479890582973deaf.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-7af00f72cf694077.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-f7753e9effae3816.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-f3e6e74e0efb005c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-4d658222ec800511.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-2fcd95c41e578d57.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-a3275554ffe8e640.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers/[key]-77239269acc2d31a.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers/new-8bf1821722b082e9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers-8d92be437793c96f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/privacy-requests-97221067330c0c27.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-2deb6becece69d46.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-6c91bdea40875227.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-3059aba38adefa56.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/webpack-2766492c5dbceb0a.js +0 -1
- fides/ui-build/static/admin/_next/static/css/073713cd1eddda79.css +0 -1
- fides/ui-build/static/admin/_next/static/css/23cf870196941c9a.css +0 -1
- fides/ui-build/static/admin/_next/static/css/295d729ea1b11885.css +0 -1
- fides/ui-build/static/admin/_next/static/css/304c6f148886a8d4.css +0 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +0 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +0 -1
- fides/ui-build/static/admin/messaging/[id].html +0 -1
- fides/ui-build/static/admin/messaging/add-template.html +0 -1
- fides/ui-build/static/admin/messaging.html +0 -1
- fides/ui-build/static/admin/settings/messaging-providers/[key].html +0 -1
- fides/ui-build/static/admin/settings/messaging-providers/new.html +0 -1
- fides/ui-build/static/admin/settings/messaging-providers.html +0 -1
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.74.0rc1.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.74.0rc1.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.74.0rc1.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.74.0rc1.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{_IxwgneyQjdSaZFEF3Tqu → FZTEUgamBvOhgPWce135w}/_ssgManifest.js +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/user-management/{new-629c88e90699369b.js → new-7dce2916cc589c54.js} +0 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
from datetime import datetime, timedelta, timezone
|
|
2
|
+
from typing import Optional
|
|
3
|
+
from uuid import UUID
|
|
4
|
+
|
|
5
|
+
from loguru import logger
|
|
6
|
+
from sqlalchemy.orm import Session
|
|
7
|
+
|
|
8
|
+
from fides.api.models.privacy_request.duplicate_group import (
|
|
9
|
+
DuplicateGroup,
|
|
10
|
+
generate_rule_version,
|
|
11
|
+
)
|
|
12
|
+
from fides.api.models.privacy_request.privacy_request import PrivacyRequest
|
|
13
|
+
from fides.api.schemas.policy import ActionType
|
|
14
|
+
from fides.api.schemas.privacy_request import PrivacyRequestStatus
|
|
15
|
+
from fides.api.task.conditional_dependencies.schemas import (
|
|
16
|
+
Condition,
|
|
17
|
+
ConditionGroup,
|
|
18
|
+
ConditionLeaf,
|
|
19
|
+
GroupOperator,
|
|
20
|
+
Operator,
|
|
21
|
+
)
|
|
22
|
+
from fides.api.task.conditional_dependencies.sql_translator import (
|
|
23
|
+
SQLConditionTranslator,
|
|
24
|
+
)
|
|
25
|
+
from fides.config.config_proxy import ConfigProxy
|
|
26
|
+
from fides.config.duplicate_detection_settings import DuplicateDetectionSettings
|
|
27
|
+
|
|
28
|
+
ACTIONED_REQUEST_STATUSES = [
|
|
29
|
+
PrivacyRequestStatus.approved,
|
|
30
|
+
PrivacyRequestStatus.in_processing,
|
|
31
|
+
PrivacyRequestStatus.requires_manual_finalization,
|
|
32
|
+
PrivacyRequestStatus.requires_input,
|
|
33
|
+
PrivacyRequestStatus.paused,
|
|
34
|
+
PrivacyRequestStatus.awaiting_email_send,
|
|
35
|
+
PrivacyRequestStatus.error,
|
|
36
|
+
]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class DuplicateDetectionService:
|
|
40
|
+
def __init__(self, db: Session):
|
|
41
|
+
self.db = db
|
|
42
|
+
self._config = ConfigProxy(db).privacy_request_duplicate_detection
|
|
43
|
+
|
|
44
|
+
def is_enabled(self) -> bool:
|
|
45
|
+
return self._config.enabled
|
|
46
|
+
|
|
47
|
+
def _create_identity_conditions(
|
|
48
|
+
self, current_request: PrivacyRequest
|
|
49
|
+
) -> list[Condition]:
|
|
50
|
+
"""Creates conditions for matching identity fields.
|
|
51
|
+
|
|
52
|
+
For identity field matching using the EAV pattern in ProvidedIdentity, we need to match both field_name
|
|
53
|
+
and hashed_value. This function creates the required nested conditions for each identity field.
|
|
54
|
+
Also adds a condition for the policy_id to ensure that we are only matching requests for the same policy.
|
|
55
|
+
"""
|
|
56
|
+
conditions: list[Condition] = []
|
|
57
|
+
current_identities: dict[str, str] = {
|
|
58
|
+
pi.field_name: pi.hashed_value
|
|
59
|
+
for pi in current_request.provided_identities # type: ignore [attr-defined]
|
|
60
|
+
if pi.field_name in self._config.match_identity_fields
|
|
61
|
+
}
|
|
62
|
+
if len(current_identities) != len(self._config.match_identity_fields):
|
|
63
|
+
missing_fields = [
|
|
64
|
+
field
|
|
65
|
+
for field in self._config.match_identity_fields
|
|
66
|
+
if field not in current_identities.keys()
|
|
67
|
+
]
|
|
68
|
+
logger.debug(
|
|
69
|
+
f"Some identity fields were not found in the current request: {missing_fields}"
|
|
70
|
+
)
|
|
71
|
+
return []
|
|
72
|
+
|
|
73
|
+
for field_name, hashed_value in current_identities.items():
|
|
74
|
+
identity_condition = ConditionGroup(
|
|
75
|
+
logical_operator=GroupOperator.and_,
|
|
76
|
+
conditions=[
|
|
77
|
+
ConditionLeaf(
|
|
78
|
+
field_address="privacyrequest.provided_identities.field_name",
|
|
79
|
+
operator=Operator.eq,
|
|
80
|
+
value=field_name,
|
|
81
|
+
),
|
|
82
|
+
ConditionLeaf(
|
|
83
|
+
field_address="privacyrequest.provided_identities.hashed_value",
|
|
84
|
+
operator=Operator.eq,
|
|
85
|
+
value=hashed_value,
|
|
86
|
+
),
|
|
87
|
+
],
|
|
88
|
+
)
|
|
89
|
+
conditions.append(identity_condition)
|
|
90
|
+
policy_condition = ConditionLeaf(
|
|
91
|
+
field_address="privacyrequest.policy_id",
|
|
92
|
+
operator=Operator.eq,
|
|
93
|
+
value=current_request.policy_id,
|
|
94
|
+
)
|
|
95
|
+
conditions.append(policy_condition)
|
|
96
|
+
return conditions
|
|
97
|
+
|
|
98
|
+
def _create_time_window_condition(self, time_window_days: int) -> Condition:
|
|
99
|
+
"""Creates a condition for matching requests within a time window."""
|
|
100
|
+
cutoff_date = datetime.now(timezone.utc) - timedelta(days=time_window_days)
|
|
101
|
+
condition = ConditionLeaf(
|
|
102
|
+
field_address="privacyrequest.created_at",
|
|
103
|
+
operator=Operator.gte,
|
|
104
|
+
value=cutoff_date.isoformat(),
|
|
105
|
+
)
|
|
106
|
+
return condition
|
|
107
|
+
|
|
108
|
+
def create_duplicate_detection_conditions(
|
|
109
|
+
self,
|
|
110
|
+
current_request: PrivacyRequest,
|
|
111
|
+
) -> Optional[ConditionGroup]:
|
|
112
|
+
"""
|
|
113
|
+
Create conditions for duplicate detection based on configuration.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
current_request: The current privacy request to find duplicates for
|
|
117
|
+
config: Duplicate detection configuration settings
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
A ConditionGroup with AND operator, or None if no conditions can be created
|
|
121
|
+
"""
|
|
122
|
+
if len(self._config.match_identity_fields) == 0:
|
|
123
|
+
return None
|
|
124
|
+
|
|
125
|
+
identity_conditions = self._create_identity_conditions(current_request)
|
|
126
|
+
if not identity_conditions:
|
|
127
|
+
return None # Only proceed if we have identity conditions
|
|
128
|
+
|
|
129
|
+
time_window_condition = self._create_time_window_condition(
|
|
130
|
+
self._config.time_window_days
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
# Combine all conditions with AND operator
|
|
134
|
+
all_conditions: list[Condition] = [*identity_conditions, time_window_condition]
|
|
135
|
+
return ConditionGroup(
|
|
136
|
+
logical_operator=GroupOperator.and_, conditions=all_conditions
|
|
137
|
+
)
|
|
138
|
+
|
|
139
|
+
def find_duplicate_privacy_requests(
|
|
140
|
+
self,
|
|
141
|
+
current_request: PrivacyRequest,
|
|
142
|
+
) -> list[PrivacyRequest]:
|
|
143
|
+
"""
|
|
144
|
+
Find potential duplicate privacy requests based on duplicate detection configuration.
|
|
145
|
+
|
|
146
|
+
Uses the SQLConditionTranslator to build queries from conditions, which handles
|
|
147
|
+
the ProvidedIdentity relationship using SQLAlchemy's .any() method.
|
|
148
|
+
|
|
149
|
+
Args:
|
|
150
|
+
current_request: The privacy request to check for duplicates
|
|
151
|
+
config: Duplicate detection configuration settings
|
|
152
|
+
|
|
153
|
+
Returns:
|
|
154
|
+
List of PrivacyRequest objects that match the duplicate criteria,
|
|
155
|
+
does not include the current request
|
|
156
|
+
"""
|
|
157
|
+
condition = self.create_duplicate_detection_conditions(current_request)
|
|
158
|
+
|
|
159
|
+
if condition is None:
|
|
160
|
+
return []
|
|
161
|
+
|
|
162
|
+
translator = SQLConditionTranslator(self.db)
|
|
163
|
+
query = translator.generate_query_from_condition(condition)
|
|
164
|
+
|
|
165
|
+
query = query.filter(PrivacyRequest.id != current_request.id).filter(
|
|
166
|
+
PrivacyRequest.deleted_at.is_(None)
|
|
167
|
+
)
|
|
168
|
+
return query.all()
|
|
169
|
+
|
|
170
|
+
def generate_dedup_key(self, request: PrivacyRequest) -> str:
|
|
171
|
+
"""
|
|
172
|
+
Generate a dedup key for a request based on the duplicate detection settings.
|
|
173
|
+
"""
|
|
174
|
+
current_identities: dict[str, str] = {
|
|
175
|
+
pi.field_name: pi.hashed_value
|
|
176
|
+
for pi in request.provided_identities # type: ignore [attr-defined]
|
|
177
|
+
if pi.field_name in self._config.match_identity_fields
|
|
178
|
+
}
|
|
179
|
+
if len(current_identities) != len(self._config.match_identity_fields):
|
|
180
|
+
raise ValueError(
|
|
181
|
+
"This request does not contain the required identity fields for duplicate detection."
|
|
182
|
+
)
|
|
183
|
+
return "|".join(
|
|
184
|
+
[
|
|
185
|
+
current_identities[field]
|
|
186
|
+
for field in sorted(self._config.match_identity_fields)
|
|
187
|
+
]
|
|
188
|
+
)
|
|
189
|
+
|
|
190
|
+
def update_duplicate_group_ids(
|
|
191
|
+
self,
|
|
192
|
+
request: PrivacyRequest,
|
|
193
|
+
duplicates: list[PrivacyRequest],
|
|
194
|
+
duplicate_group_id: UUID,
|
|
195
|
+
) -> None:
|
|
196
|
+
"""
|
|
197
|
+
Update the duplicate request group ids for a request and its duplicates.
|
|
198
|
+
Args:
|
|
199
|
+
request: The privacy request to update
|
|
200
|
+
duplicates: The list of duplicate requests to update
|
|
201
|
+
duplicate_group_id: The duplicate request group id to update
|
|
202
|
+
"""
|
|
203
|
+
update_all = [request] + duplicates
|
|
204
|
+
try:
|
|
205
|
+
for privacy_request in update_all:
|
|
206
|
+
privacy_request.duplicate_request_group_id = duplicate_group_id # type: ignore [assignment]
|
|
207
|
+
except Exception as e:
|
|
208
|
+
logger.error(f"Failed to update duplicate request group ids: {e}")
|
|
209
|
+
raise e
|
|
210
|
+
|
|
211
|
+
def mark_as_duplicate(self, request: PrivacyRequest, message: str) -> None:
|
|
212
|
+
"""
|
|
213
|
+
Mark a request as a duplicate.
|
|
214
|
+
"""
|
|
215
|
+
request.update(self.db, data={"status": PrivacyRequestStatus.duplicate})
|
|
216
|
+
logger.debug(message)
|
|
217
|
+
self.add_error_execution_log(request, message)
|
|
218
|
+
|
|
219
|
+
def add_error_execution_log(self, request: PrivacyRequest, message: str) -> None:
|
|
220
|
+
request.add_error_execution_log(
|
|
221
|
+
db=self.db,
|
|
222
|
+
connection_key=None,
|
|
223
|
+
dataset_name="Duplicate Request Detection",
|
|
224
|
+
collection_name=None,
|
|
225
|
+
message=message,
|
|
226
|
+
action_type=(
|
|
227
|
+
request.policy.get_action_type() # type: ignore [arg-type]
|
|
228
|
+
if request.policy
|
|
229
|
+
else ActionType.access
|
|
230
|
+
),
|
|
231
|
+
)
|
|
232
|
+
|
|
233
|
+
def add_success_execution_log(self, request: PrivacyRequest, message: str) -> None:
|
|
234
|
+
request.add_success_execution_log(
|
|
235
|
+
db=self.db,
|
|
236
|
+
connection_key=None,
|
|
237
|
+
dataset_name="Duplicate Request Detection",
|
|
238
|
+
collection_name=None,
|
|
239
|
+
message=message,
|
|
240
|
+
action_type=(
|
|
241
|
+
request.policy.get_action_type() # type: ignore [arg-type]
|
|
242
|
+
if request.policy
|
|
243
|
+
else ActionType.access
|
|
244
|
+
),
|
|
245
|
+
)
|
|
246
|
+
|
|
247
|
+
def verified_identity_cases(
|
|
248
|
+
self, request: PrivacyRequest, duplicates: list[PrivacyRequest]
|
|
249
|
+
) -> bool:
|
|
250
|
+
"""
|
|
251
|
+
Apply verified identity rules to determine if a request is a duplicate request.
|
|
252
|
+
- If this request does not have a verified identity, it may be a duplicate if another request in the group is verified.
|
|
253
|
+
- If this is the first request to be verified, it is not a duplicate request
|
|
254
|
+
- If other requests identities were verified before this request, it is a duplicate request
|
|
255
|
+
Args:
|
|
256
|
+
request: The privacy request to check
|
|
257
|
+
duplicates: The list of duplicate requests
|
|
258
|
+
|
|
259
|
+
Returns:
|
|
260
|
+
True if the request is a duplicate request, False otherwise
|
|
261
|
+
"""
|
|
262
|
+
verified_in_group = [
|
|
263
|
+
duplicate for duplicate in duplicates if duplicate.identity_verified_at
|
|
264
|
+
]
|
|
265
|
+
|
|
266
|
+
# The request identity is not verified.
|
|
267
|
+
if not request.identity_verified_at:
|
|
268
|
+
if len(verified_in_group) > 0:
|
|
269
|
+
message = f"Request {request.id} is a duplicate: it is duplicating request(s) {[duplicate.id for duplicate in verified_in_group]}."
|
|
270
|
+
self.mark_as_duplicate(request, message)
|
|
271
|
+
return True
|
|
272
|
+
|
|
273
|
+
canonical_request = min(duplicates, key=lambda x: x.created_at) # type: ignore [arg-type, return-value]
|
|
274
|
+
canonical_request_created_at = canonical_request.created_at or datetime.now(
|
|
275
|
+
timezone.utc
|
|
276
|
+
)
|
|
277
|
+
request_created_at = request.created_at or datetime.now(timezone.utc)
|
|
278
|
+
if request_created_at < canonical_request_created_at:
|
|
279
|
+
message = f"Request {request.id} is not a duplicate: it is the first request to be created in the group."
|
|
280
|
+
logger.debug(message)
|
|
281
|
+
self.add_success_execution_log(request, message)
|
|
282
|
+
return False
|
|
283
|
+
|
|
284
|
+
message = f"Request {request.id} is a duplicate: it is duplicating request(s) ['{canonical_request.id}']."
|
|
285
|
+
self.mark_as_duplicate(request, message)
|
|
286
|
+
return True
|
|
287
|
+
|
|
288
|
+
# The request identity is verified.
|
|
289
|
+
if not verified_in_group:
|
|
290
|
+
message = f"Request {request.id} is not a duplicate: it is the first request to be verified in the group."
|
|
291
|
+
logger.debug(message)
|
|
292
|
+
for duplicate in duplicates:
|
|
293
|
+
dup_message = f"Request {duplicate.id} is a duplicate: it is duplicating request(s) ['{request.id}']."
|
|
294
|
+
self.mark_as_duplicate(duplicate, dup_message)
|
|
295
|
+
self.add_success_execution_log(request, message)
|
|
296
|
+
return False
|
|
297
|
+
|
|
298
|
+
# If this request is the first with a verified identity, it is not a duplicate.
|
|
299
|
+
canonical_request = min(verified_in_group, key=lambda x: x.identity_verified_at) # type: ignore [arg-type, return-value]
|
|
300
|
+
canonical_request_verified_at = (
|
|
301
|
+
canonical_request.identity_verified_at or datetime.now(timezone.utc)
|
|
302
|
+
)
|
|
303
|
+
request_verified_at = request.identity_verified_at or datetime.now(timezone.utc)
|
|
304
|
+
if request_verified_at < canonical_request_verified_at:
|
|
305
|
+
message = f"Request {request.id} is not a duplicate: it is the first request to be verified in the group."
|
|
306
|
+
logger.debug(message)
|
|
307
|
+
self.add_success_execution_log(request, message)
|
|
308
|
+
for duplicate in duplicates:
|
|
309
|
+
dup_message = f"Request {duplicate.id} is a duplicate: it is duplicating request(s) ['{request.id}']."
|
|
310
|
+
self.mark_as_duplicate(duplicate, dup_message)
|
|
311
|
+
return False
|
|
312
|
+
message = f"Request {request.id} is a duplicate: it is duplicating request(s) ['{canonical_request.id}']."
|
|
313
|
+
self.mark_as_duplicate(request, message)
|
|
314
|
+
return True
|
|
315
|
+
|
|
316
|
+
# pylint: disable=too-many-return-statements
|
|
317
|
+
def is_duplicate_request(self, request: PrivacyRequest) -> bool:
|
|
318
|
+
"""
|
|
319
|
+
Determine if a request is a duplicate request and assigns a duplicate request group id.
|
|
320
|
+
|
|
321
|
+
The hierarchy is:
|
|
322
|
+
1. Actioned requests: if this request duplicates an actioned request, it is a duplicate.
|
|
323
|
+
2. Verified identity requests:
|
|
324
|
+
a. if this request has a verified identity:
|
|
325
|
+
- If none of the duplicates have a verified identity, it is not a duplicate.
|
|
326
|
+
- If duplicates have verified identities, but this request is the first with a verified identity, it is not a duplicate.
|
|
327
|
+
b. if this request does not have a verified identity:
|
|
328
|
+
- If no duplicates have a verified identity, and this was the first created request, it is not a duplicate.
|
|
329
|
+
3. First created request: if this is the first created request in the group, it is not a duplicate.
|
|
330
|
+
4. If no canonical requests are found (meaning all requests are marked as duplicates), this request is not a duplicate.
|
|
331
|
+
- Could occur if configuration changes and previous requests were already marked as duplicates.
|
|
332
|
+
|
|
333
|
+
Args:
|
|
334
|
+
request: The privacy request to check
|
|
335
|
+
config: Duplicate detection configuration settings
|
|
336
|
+
Returns:
|
|
337
|
+
True if the request is a duplicate request, False otherwise
|
|
338
|
+
"""
|
|
339
|
+
if request.policy.get_action_type() == ActionType.consent:
|
|
340
|
+
message = f"Consent request {request.id} is not a duplicate."
|
|
341
|
+
logger.info(message)
|
|
342
|
+
self.add_success_execution_log(request, message)
|
|
343
|
+
return False
|
|
344
|
+
duplicates = self.find_duplicate_privacy_requests(request)
|
|
345
|
+
rule_version = generate_rule_version(
|
|
346
|
+
DuplicateDetectionSettings(
|
|
347
|
+
enabled=self._config.enabled,
|
|
348
|
+
time_window_days=self._config.time_window_days,
|
|
349
|
+
match_identity_fields=self._config.match_identity_fields,
|
|
350
|
+
)
|
|
351
|
+
)
|
|
352
|
+
try:
|
|
353
|
+
dedup_key = self.generate_dedup_key(request)
|
|
354
|
+
except ValueError as e:
|
|
355
|
+
message = f"Request {request.id} is not a duplicate: {e}"
|
|
356
|
+
logger.warning(message)
|
|
357
|
+
self.add_success_execution_log(request, message)
|
|
358
|
+
return False
|
|
359
|
+
|
|
360
|
+
_, duplicate_group = DuplicateGroup.get_or_create(
|
|
361
|
+
db=self.db, data={"rule_version": rule_version, "dedup_key": dedup_key}
|
|
362
|
+
)
|
|
363
|
+
if duplicate_group is None:
|
|
364
|
+
message = f"Failed to create duplicate group for request {request.id} with dedup key {dedup_key}"
|
|
365
|
+
logger.error(message)
|
|
366
|
+
self.add_error_execution_log(request, message)
|
|
367
|
+
return False
|
|
368
|
+
|
|
369
|
+
self.update_duplicate_group_ids(request, duplicates, duplicate_group.id) # type: ignore [arg-type]
|
|
370
|
+
|
|
371
|
+
if request.status in ACTIONED_REQUEST_STATUSES:
|
|
372
|
+
message = (
|
|
373
|
+
f"Request {request.id} is not a duplicate: it is an actioned request."
|
|
374
|
+
)
|
|
375
|
+
logger.debug(message)
|
|
376
|
+
self.add_success_execution_log(request, message)
|
|
377
|
+
return False
|
|
378
|
+
|
|
379
|
+
# if this is the only request in the group, it is not a duplicate
|
|
380
|
+
if len(duplicates) == 0:
|
|
381
|
+
message = f"Request {request.id} is not a duplicate."
|
|
382
|
+
logger.debug(message)
|
|
383
|
+
self.add_success_execution_log(request, message)
|
|
384
|
+
return False
|
|
385
|
+
|
|
386
|
+
if request.status == PrivacyRequestStatus.duplicate:
|
|
387
|
+
return True
|
|
388
|
+
|
|
389
|
+
# only compare to non-duplicate/complete requests for the following cases
|
|
390
|
+
canonical_requests = [
|
|
391
|
+
duplicate
|
|
392
|
+
for duplicate in duplicates
|
|
393
|
+
if duplicate.status
|
|
394
|
+
not in [PrivacyRequestStatus.duplicate, PrivacyRequestStatus.complete]
|
|
395
|
+
]
|
|
396
|
+
# If no non-duplicate requests are found, this request is not a duplicate.
|
|
397
|
+
if len(canonical_requests) == 0:
|
|
398
|
+
message = f"Request {request.id} is not a duplicate."
|
|
399
|
+
logger.debug(message)
|
|
400
|
+
self.add_success_execution_log(request, message)
|
|
401
|
+
return False
|
|
402
|
+
|
|
403
|
+
# If any requests in group are actioned, this request is a duplicate.
|
|
404
|
+
actioned_in_group = [
|
|
405
|
+
duplicate
|
|
406
|
+
for duplicate in canonical_requests
|
|
407
|
+
if duplicate.status in ACTIONED_REQUEST_STATUSES
|
|
408
|
+
]
|
|
409
|
+
if len(actioned_in_group) > 0:
|
|
410
|
+
message = f"Request {request.id} is a duplicate: it is duplicating actioned request(s) {[duplicate.id for duplicate in actioned_in_group]}."
|
|
411
|
+
self.mark_as_duplicate(request, message)
|
|
412
|
+
return True
|
|
413
|
+
# Check against verified identity rules.
|
|
414
|
+
return self.verified_identity_cases(request, canonical_requests)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def check_for_duplicates(db: Session, privacy_request: PrivacyRequest) -> None:
|
|
418
|
+
duplicate_detection_service = DuplicateDetectionService(db)
|
|
419
|
+
if duplicate_detection_service.is_enabled():
|
|
420
|
+
logger.info(
|
|
421
|
+
"Duplicate detection is enabled. Checking if privacy request is a duplicate."
|
|
422
|
+
)
|
|
423
|
+
if duplicate_detection_service.is_duplicate_request(privacy_request):
|
|
424
|
+
logger.info("Terminating privacy request: request is a duplicate.")
|
|
@@ -2,10 +2,13 @@
|
|
|
2
2
|
import time
|
|
3
3
|
from copy import deepcopy
|
|
4
4
|
from datetime import datetime, timedelta
|
|
5
|
-
from typing import Any, Optional
|
|
5
|
+
from typing import Any, Optional
|
|
6
6
|
|
|
7
|
-
import
|
|
7
|
+
import sqlalchemy.exc
|
|
8
8
|
from loguru import logger
|
|
9
|
+
|
|
10
|
+
# pylint: disable=no-name-in-module
|
|
11
|
+
from psycopg2.errors import InternalError_ # type: ignore[import-untyped]
|
|
9
12
|
from pydantic import ValidationError as PydanticValidationError
|
|
10
13
|
from sqlalchemy.orm import Query, Session
|
|
11
14
|
|
|
@@ -22,7 +25,6 @@ from fides.api.common_exceptions import (
|
|
|
22
25
|
ValidationError,
|
|
23
26
|
)
|
|
24
27
|
from fides.api.db.session import get_db_session
|
|
25
|
-
from fides.api.graph.config import CollectionAddress
|
|
26
28
|
from fides.api.graph.graph import DatasetGraph
|
|
27
29
|
from fides.api.models.attachment import Attachment, AttachmentReferenceType
|
|
28
30
|
from fides.api.models.audit_log import AuditLog, AuditLogAction
|
|
@@ -53,7 +55,7 @@ from fides.api.schemas.policy import ActionType, CurrentStep
|
|
|
53
55
|
from fides.api.schemas.privacy_request import PrivacyRequestStatus
|
|
54
56
|
from fides.api.schemas.redis_cache import Identity
|
|
55
57
|
from fides.api.schemas.storage.storage import StorageType
|
|
56
|
-
from fides.api.service.connectors import
|
|
58
|
+
from fides.api.service.connectors import get_connector
|
|
57
59
|
from fides.api.service.connectors.consent_email_connector import (
|
|
58
60
|
CONSENT_EMAIL_CONNECTOR_TYPES,
|
|
59
61
|
)
|
|
@@ -69,6 +71,7 @@ from fides.api.service.privacy_request.attachment_handling import (
|
|
|
69
71
|
get_attachments_content,
|
|
70
72
|
process_attachments_for_upload,
|
|
71
73
|
)
|
|
74
|
+
from fides.api.service.privacy_request.duplication_detection import check_for_duplicates
|
|
72
75
|
from fides.api.service.storage.storage_uploader_service import upload
|
|
73
76
|
from fides.api.task.filter_results import filter_data_categories
|
|
74
77
|
from fides.api.task.graph_runners import access_runner, consent_runner, erasure_runner
|
|
@@ -85,11 +88,7 @@ from fides.api.util.collection_util import Row
|
|
|
85
88
|
from fides.api.util.logger import Pii, _log_exception, _log_warning
|
|
86
89
|
from fides.api.util.logger_context_utils import LoggerContextKeys, log_context
|
|
87
90
|
from fides.api.util.memory_watchdog import memory_limiter
|
|
88
|
-
from fides.common.api.v1.urn_registry import
|
|
89
|
-
PRIVACY_CENTER_DSR_PACKAGE,
|
|
90
|
-
PRIVACY_REQUEST_TRANSFER_TO_PARENT,
|
|
91
|
-
V1_URL_PREFIX,
|
|
92
|
-
)
|
|
91
|
+
from fides.common.api.v1.urn_registry import PRIVACY_CENTER_DSR_PACKAGE
|
|
93
92
|
from fides.config import CONFIG
|
|
94
93
|
from fides.config.config_proxy import ConfigProxy
|
|
95
94
|
|
|
@@ -276,6 +275,11 @@ def upload_access_results(
|
|
|
276
275
|
return download_urls
|
|
277
276
|
|
|
278
277
|
|
|
278
|
+
@log_context(
|
|
279
|
+
capture_args={
|
|
280
|
+
"privacy_request_id": LoggerContextKeys.privacy_request_id,
|
|
281
|
+
}
|
|
282
|
+
)
|
|
279
283
|
def save_access_results(
|
|
280
284
|
session: Session,
|
|
281
285
|
privacy_request: PrivacyRequest,
|
|
@@ -284,12 +288,34 @@ def save_access_results(
|
|
|
284
288
|
) -> None:
|
|
285
289
|
"""Save the results we uploaded to the user for later retrieval"""
|
|
286
290
|
# Save the results we uploaded to the user for later retrieval
|
|
287
|
-
privacy_request.save_filtered_access_results(session, rule_filtered_results)
|
|
288
291
|
# Saving access request URL's on the privacy request in case DSR 3.0
|
|
289
292
|
# exits processing before the email is sent
|
|
290
293
|
privacy_request.access_result_urls = {"access_result_urls": download_urls}
|
|
291
294
|
privacy_request.save(session)
|
|
292
295
|
|
|
296
|
+
# Try to save the backup results, but don't fail the DSR if this fails
|
|
297
|
+
try:
|
|
298
|
+
privacy_request.save_filtered_access_results(session, rule_filtered_results)
|
|
299
|
+
logger.info("Successfully saved backup filtered access results to database")
|
|
300
|
+
except (
|
|
301
|
+
InternalError_, # invalid memory alloc request size 1073741824
|
|
302
|
+
sqlalchemy.exc.StatementError, # SQL statement errors
|
|
303
|
+
# Python memory errors
|
|
304
|
+
MemoryError, # system out of memory
|
|
305
|
+
OverflowError, # numeric overflow during serialization
|
|
306
|
+
) as exc:
|
|
307
|
+
logger.warning(
|
|
308
|
+
"Failed to save backup of DSR results to database after successful S3 upload. "
|
|
309
|
+
"DSR will continue processing. Error: {}",
|
|
310
|
+
str(exc),
|
|
311
|
+
)
|
|
312
|
+
except Exception as exc:
|
|
313
|
+
logger.error(
|
|
314
|
+
"Failed to save backup of DSR results to database after successful S3 upload. "
|
|
315
|
+
"DSR will continue processing. Unexpected Error: {}",
|
|
316
|
+
str(exc),
|
|
317
|
+
)
|
|
318
|
+
|
|
293
319
|
|
|
294
320
|
@log_context(
|
|
295
321
|
capture_args={
|
|
@@ -307,8 +333,11 @@ def upload_and_save_access_results( # pylint: disable=R0912
|
|
|
307
333
|
) -> list[str]:
|
|
308
334
|
"""Process the data uploads after the access portion of the privacy request has completed"""
|
|
309
335
|
download_urls: list[str] = []
|
|
310
|
-
# Remove manual webhook attachments from the list of attachments
|
|
311
|
-
# This is done because
|
|
336
|
+
# Remove manual webhook attachments and request task attachments from the list of attachments
|
|
337
|
+
# This is done because:
|
|
338
|
+
# - manual webhook attachments are already included in the manual_data
|
|
339
|
+
# - manual task submission attachments are already included in the manual_data
|
|
340
|
+
# - request task attachments (from async polling) are already embedded in the dataset results
|
|
312
341
|
loaded_attachments = [
|
|
313
342
|
attachment
|
|
314
343
|
for attachment in privacy_request.attachments
|
|
@@ -317,6 +346,7 @@ def upload_and_save_access_results( # pylint: disable=R0912
|
|
|
317
346
|
in [
|
|
318
347
|
AttachmentReferenceType.access_manual_webhook,
|
|
319
348
|
AttachmentReferenceType.manual_task_submission,
|
|
349
|
+
AttachmentReferenceType.request_task,
|
|
320
350
|
]
|
|
321
351
|
for ref in attachment.references
|
|
322
352
|
)
|
|
@@ -417,6 +447,10 @@ def run_privacy_request(
|
|
|
417
447
|
logger.info("Terminating privacy request: request deleted.")
|
|
418
448
|
return
|
|
419
449
|
|
|
450
|
+
check_for_duplicates(db=session, privacy_request=privacy_request)
|
|
451
|
+
if privacy_request.status == PrivacyRequestStatus.duplicate:
|
|
452
|
+
return
|
|
453
|
+
|
|
420
454
|
logger.info("Dispatching privacy request")
|
|
421
455
|
privacy_request.start_processing(session)
|
|
422
456
|
|
|
@@ -922,78 +956,6 @@ def mark_paused_privacy_request_as_expired(privacy_request_id: str) -> None:
|
|
|
922
956
|
db.close()
|
|
923
957
|
|
|
924
958
|
|
|
925
|
-
def _retrieve_child_results( # pylint: disable=R0911
|
|
926
|
-
fides_connector: Tuple[str, ConnectionConfig],
|
|
927
|
-
rule_key: str,
|
|
928
|
-
access_result: dict[str, list[Row]],
|
|
929
|
-
) -> Optional[list[dict[str, Optional[list[Row]]]]]:
|
|
930
|
-
"""Get child access request results to add to upload."""
|
|
931
|
-
try:
|
|
932
|
-
connector = FidesConnector(fides_connector[1])
|
|
933
|
-
except Exception as e:
|
|
934
|
-
logger.error(
|
|
935
|
-
"Error create client for child server {}: {}", fides_connector[0], e
|
|
936
|
-
)
|
|
937
|
-
return None
|
|
938
|
-
|
|
939
|
-
results = []
|
|
940
|
-
|
|
941
|
-
for key, rows in access_result.items():
|
|
942
|
-
address = CollectionAddress.from_string(key)
|
|
943
|
-
privacy_request_id = None
|
|
944
|
-
if address.dataset == fides_connector[0]:
|
|
945
|
-
if not rows:
|
|
946
|
-
logger.info("No rows found for result entry {}", key)
|
|
947
|
-
continue
|
|
948
|
-
privacy_request_id = rows[0]["id"]
|
|
949
|
-
|
|
950
|
-
if not privacy_request_id:
|
|
951
|
-
logger.error(
|
|
952
|
-
"No privacy request found for connector key {}", fides_connector[0]
|
|
953
|
-
)
|
|
954
|
-
continue
|
|
955
|
-
|
|
956
|
-
try:
|
|
957
|
-
client = connector.create_client()
|
|
958
|
-
except requests.exceptions.HTTPError as e:
|
|
959
|
-
logger.error(
|
|
960
|
-
"Error logger into to child server for privacy request {}: {}",
|
|
961
|
-
privacy_request_id,
|
|
962
|
-
e,
|
|
963
|
-
)
|
|
964
|
-
continue
|
|
965
|
-
|
|
966
|
-
try:
|
|
967
|
-
request = client.authenticated_request(
|
|
968
|
-
method="get",
|
|
969
|
-
path=f"{V1_URL_PREFIX}{PRIVACY_REQUEST_TRANSFER_TO_PARENT.format(privacy_request_id=privacy_request_id, rule_key=rule_key)}",
|
|
970
|
-
headers={"Authorization": f"Bearer {client.token}"},
|
|
971
|
-
)
|
|
972
|
-
response = client.session.send(request)
|
|
973
|
-
except requests.exceptions.HTTPError as e:
|
|
974
|
-
logger.error(
|
|
975
|
-
"Error retrieving data from child server for privacy request {}: {}",
|
|
976
|
-
privacy_request_id,
|
|
977
|
-
e,
|
|
978
|
-
)
|
|
979
|
-
continue
|
|
980
|
-
|
|
981
|
-
if response.status_code != 200:
|
|
982
|
-
logger.error(
|
|
983
|
-
"Error retrieving data from child server for privacy request {}: {}",
|
|
984
|
-
privacy_request_id,
|
|
985
|
-
response.json(),
|
|
986
|
-
)
|
|
987
|
-
continue
|
|
988
|
-
|
|
989
|
-
results.append(response.json())
|
|
990
|
-
|
|
991
|
-
if not results:
|
|
992
|
-
return None
|
|
993
|
-
|
|
994
|
-
return results
|
|
995
|
-
|
|
996
|
-
|
|
997
959
|
def get_consent_email_connection_configs(db: Session) -> Query:
|
|
998
960
|
"""Return enabled consent email connection configs."""
|
|
999
961
|
return db.query(ConnectionConfig).filter(
|