ethyca-fides 2.71.1b1__py2.py3-none-any.whl → 2.71.2b0__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.71.2b0.dist-info}/METADATA +1 -1
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/RECORD +262 -248
- fides/_version.py +3 -3
- 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/b97e92b038d2_add_digest_execution_model.py +117 -0
- fides/api/common_exceptions.py +4 -0
- fides/api/main.py +2 -2
- fides/api/models/attachment.py +1 -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 +132 -0
- fides/api/models/event_audit.py +8 -0
- fides/api/models/privacy_request/privacy_request.py +1 -1
- 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 +20 -5
- fides/api/service/connectors/saas_connector.py +86 -70
- 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/api/util/saas_util.py +1 -0
- fides/config/execution_settings.py +7 -3
- fides/data/language/languages.yml +2 -0
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/1099-27b2d4e59a569b38.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{1115-90baef2a89f361ad.js → 1115-8fb5000847f73ec7.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/1437-fb699e9d69c3e325.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/155-3d03f101c662c054.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{1817-1ad037b7d6d2f6d2.js → 1817-10b392e1dd9c4673.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{1975.78e719130cfe3fd6.js → 1975.50599b6774562644.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{2040-fdecc41a18e40bdc.js → 2040-01d5edb1802d3482.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/2397-40506a386a3a469a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{2921-66f65496c3a09316.js → 2921-edfdffa353a611e4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/3377-4c129258b4c4ea28.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3696-90c8b336bbc46782.js → 3696-259be222ea12392a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/3700-42976bfaad3b91c9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3772-aa7beafe5df5e656.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3923-98bea73b618292aa.js → 3923-fa1d71afc7dc9e6e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{401-ffe4e8436e1eceb9.js → 401-5270e3e23b08ab2b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/431-e01ee730c8ad9ece.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4817-5f9b9c9bafe888f1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{5185-51eaa78e3ed6bfb7.js → 5185-325e5435a0c7dcb7.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/5258-2d28b2c64acf5de3.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{5279-12c9cbdc67ad7b14.js → 5279-21929b12c927b022.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/549-c3b4c51f45a84a52.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{5643-10a36584c399526c.js → 5643-7583c1f8dbd83273.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{5783-d119cb132abd8a91.js → 5783-55c0387508e50f3e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6277-182efc294d413f64.js → 6277-ca31d48a33202761.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/6315-2d4e86a32fc40458.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6344-ca66a6e10d128179.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{6853-7004a8c420b1ca02.js → 6853-cb15625a713b3ef9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6954-4b24e1731c1cc3b3.js → 6954-08b59d28d7a2a43b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/7245-895bb7c6a6c797bc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{7476-d055aa931da47ac0.js → 7476-f25fce73eeb1f9c6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/7488-df17b592fbeaa1eb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{7630-d0d3a0fe3f95e971.js → 7630-71582de0e818e28f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/7773-98d34d188ae0a694.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{796-02086581996a0548.js → 796-7944f684f8945506.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/8011-56031d82d5428981.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/8373-7f940f5ac9c38b1f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9046-31b16a7e872c22be.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9070-13f237db78da586d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9330-cea1bf40f5d27e53.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{9676.b86ecbcfe5afd25d.js → 9676.1ea49d4b6e0541f2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9682-2754256aeae141bb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{9826-ccedc28e978ca9e1.js → 9826-e71887e2c4283249.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9899-15530c468d5656a1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9965-54037b6c8f36d14b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{404-2eb8aed4939f1142.js → 404-2014144a1a0fa64f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-c1c2f757b1f3da12.js → _app-9e869a44215709ed.js} +9 -9
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-4f3ba02774f27795.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-2ca59996860a33c5.js → multiple-1c9cef80deccb15d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-4adeec3bcec05f7b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-7a258b7ecd6da4b8.js → add-vendors-f7bdc2da53137ffd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-fb5017ff5fa54fcc.js → configure-a27b220fe76bdc8e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-e1e2fd704ac2d71d.js → [id]-542fd4a4322122f1.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-92182be6603c2842.js → privacy-experience-4254abef7bb52edd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-5fc78b78a51c239c.js → [id]-d31d1c233e94dc1f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-b79bcb93b5f4c734.js → new-2ea057e6217993f9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-ab54b19609bff325.js → privacy-notices-8e76cbfaf71fdcb9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-069f4e3ee96ebf77.js → properties-eb557180eded0abd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-93730a4316c0d980.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{consent-d2bf72508c3cad55.js → consent-c64589e53338e59a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-2fa4b3a58f75f81d.js → [resourceUrn]-d3d1841bc8105e56.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-8cd4d1d6ba000333.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-69b429a9d30ebaf1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-5b31e3d7727b917a.js → [resourceUrn]-791c522ad1d9a2ce.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources-8c7103ebf01d6e6a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-a53ef0161235ee47.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-f85f4f8fcf1bfbdb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/data-explorer-3619e454763dba09.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-ace848575e688200.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-53ca31c50c43007f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-f87e4a0f664f4cde.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-844a8de0d1b506e2.js → [resourceUrn]-699762cb8a66237e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-11b07cf2d91b17ef.js → detection-d970d0b82db36c88.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-5525cf287d4ab493.js → [resourceUrn]-a6343038a447699c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-ed4723e1b67d890e.js → discovery-ce82ba79f9bf825c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datamap-ae7a4c1c4eabc0d4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-179e5d09ccff50c1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-59466e5e238c59d0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-36d90c8c39fb0d1c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-db54d01fd8f6df50.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-55d312af5228e098.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-488beba62e832660.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-4aad5495f9bf81ce.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-496ec7ecca8259dc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{index-b74d1e8608ae5b5d.js → index-8a2ba955d92d52ee.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-4580f70eb41b6a7d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-f69b04d3b4cf43b1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-e8d2140787045acd.js → [id]-d6eed2dc5d27f625.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-e3f93462a08251bf.js → add-template-c7b43fa365f4be10.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{messaging-b5f7d6afdecd013d.js → messaging-c7ba755c2e0e2377.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/{ant-components-248ad9f65a872442.js → ant-components-f14bfd5890a0e939.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{AntForm-aedb66a62042b10a.js → AntForm-e4274a4d5d23eea9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikAntFormItem-018df38b7cd77fdb.js → FormikAntFormItem-f5bce1ceb0502f04.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikControlled-6ca9099d03aab817.js → FormikControlled-90b4ea9f9deca6e2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikField-0f2c90786ea005a4.js → FormikField-d6043ae8dae6ef7d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/{forms-200b51a725f8b2d1.js → forms-520ba5ae02f47bda.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/{table-migration-29fb7b39f8962650.js → table-migration-b46f432b51421fae.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-fe4ed3ad75151e36.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-de681c2d022c9e0d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-8f577df28ebca869.js → configure-04ebf2fb6fc4358a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-cd8ba2eef9085377.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-57a75c7e9659271a.js → [id]-f75a407d78857ab3.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-8964c2300206bc89.js → add-property-975ff605e1dbc09c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{properties-08472b2a6bf1d392.js → properties-e7fdf3a9a3e8c267.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-764b6ce8e030d4a1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/{[purpose_id]-f3e6e74e0efb005c.js → [purpose_id]-da78452b3c41b29e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{consent-4d658222ec800511.js → consent-6442e761ecb5c65a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-ea9baf24de35d3b1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-744f669431b84f71.js → domain-records-44d06e280990854d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domains-a3275554ffe8e640.js → domains-6f61d886aa6f5ce7.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-604790638c656fbd.js → email-templates-11148b182370fd83.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-be2a885150adc133.js → locations-33448bf0a1d53870.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers/{[key]-77239269acc2d31a.js → [key]-4a18d8135c0dbf2a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers/{new-8bf1821722b082e9.js → new-41957281b8ec26b1.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers-776258bad0941a7d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-3c86162afe9759df.js → organization-3c315036f1fc9f90.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/privacy-requests-00917525c9245a90.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-4fe3b90747d885e5.js → regulations-5d924b2f1f926b88.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-2deb6becece69d46.js → test-datasets-8067e12227210f48.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-4d470bbf199a2f9c.js → [id]-1a902922759cae76.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-277ea1f34c3714cf.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-cecea5832cb1f3b0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-98f737e735eaa0f0.js → [id]-726fbc0a34ffba1f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-562624e5461083ec.js → user-management-df9b75ab01c1a2ea.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{webpack-2766492c5dbceb0a.js → webpack-118fb4723d13c14f.js} +1 -1
- fides/ui-build/static/admin/_next/static/css/372d6a236c84613f.css +1 -0
- fides/ui-build/static/admin/_next/static/css/f38242c11f7fea64.css +1 -0
- fides/ui-build/static/admin/_next/static/zmEQMSpOBih8kmA1t-EWO/_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]/data-explorer.html +1 -0
- 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/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/_IxwgneyQjdSaZFEF3Tqu/_buildManifest.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/155-b4337d0826d5addc.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/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/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/6882-dbe0a25dcf1a8ee0.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/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/9046-b6616ba7b59d947e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9226-4a7027057f55ca2a.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-19214babd1f219e3.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/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/custom-fields-2fcd95c41e578d57.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-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/css/073713cd1eddda79.css +0 -1
- fides/ui-build/static/admin/_next/static/css/295d729ea1b11885.css +0 -1
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{_IxwgneyQjdSaZFEF3Tqu → zmEQMSpOBih8kmA1t-EWO}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Pure utility functions for async DSR operations.
|
|
3
|
+
|
|
4
|
+
This module contains utility functions with no business logic dependencies.
|
|
5
|
+
These are helper functions that can be used across the async DSR system.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from enum import Enum
|
|
9
|
+
|
|
10
|
+
# Type checking imports
|
|
11
|
+
from typing import TYPE_CHECKING, List, cast
|
|
12
|
+
|
|
13
|
+
from loguru import logger
|
|
14
|
+
from sqlalchemy.orm import Session
|
|
15
|
+
|
|
16
|
+
from fides.api.common_exceptions import PrivacyRequestError
|
|
17
|
+
from fides.api.models.connectionconfig import ConnectionConfig
|
|
18
|
+
from fides.api.models.datasetconfig import DatasetConfig
|
|
19
|
+
from fides.api.models.privacy_request.request_task import AsyncTaskType, RequestTask
|
|
20
|
+
from fides.api.schemas.saas.saas_config import SaaSRequest
|
|
21
|
+
|
|
22
|
+
if TYPE_CHECKING:
|
|
23
|
+
from fides.api.service.connectors.query_configs.saas_query_config import (
|
|
24
|
+
SaaSQueryConfig,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def has_async_requests(query_config: "SaaSQueryConfig") -> bool:
|
|
29
|
+
"""Check if any read/update/delete requests have async configuration"""
|
|
30
|
+
all_requests: List[SaaSRequest] = cast(
|
|
31
|
+
List[SaaSRequest], query_config.get_read_requests_by_identity()
|
|
32
|
+
)
|
|
33
|
+
masking_request = query_config.get_masking_request()
|
|
34
|
+
if masking_request:
|
|
35
|
+
all_requests.append(masking_request)
|
|
36
|
+
return any(request.async_config is not None for request in all_requests)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def is_polling_continuation(request_task: RequestTask) -> bool:
|
|
40
|
+
"""Check if this is a polling continuation (not initial request)"""
|
|
41
|
+
async_type_check = request_task.async_type == AsyncTaskType.polling
|
|
42
|
+
sub_requests_count = len(request_task.sub_requests)
|
|
43
|
+
|
|
44
|
+
logger.warning(
|
|
45
|
+
f"is_polling_continuation for task {request_task.id}: "
|
|
46
|
+
f"async_type={request_task.async_type} (polling={async_type_check}), "
|
|
47
|
+
f"sub_requests_count={sub_requests_count}"
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
return async_type_check and sub_requests_count > 0
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def is_callback_completion(request_task: RequestTask) -> bool:
|
|
54
|
+
"""Check if this is a completed callback request"""
|
|
55
|
+
return bool(request_task.callback_succeeded)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def is_async_request(
|
|
59
|
+
request_task: RequestTask, query_config: "SaaSQueryConfig"
|
|
60
|
+
) -> bool:
|
|
61
|
+
"""
|
|
62
|
+
Check if this is an async request (callback, continuation, or initial async).
|
|
63
|
+
|
|
64
|
+
This is the main entry point for async detection.
|
|
65
|
+
"""
|
|
66
|
+
return (
|
|
67
|
+
is_callback_completion(request_task)
|
|
68
|
+
or is_polling_continuation(request_task)
|
|
69
|
+
or has_async_requests(query_config)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class AsyncPhase(Enum):
|
|
74
|
+
"""Enum representing different phases of async DSR processing."""
|
|
75
|
+
|
|
76
|
+
callback_completion = "callback_completion"
|
|
77
|
+
polling_continuation = "polling_continuation"
|
|
78
|
+
initial_async = "initial_async"
|
|
79
|
+
sync = "sync"
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def get_async_phase(
|
|
83
|
+
request_task: RequestTask, query_config: "SaaSQueryConfig"
|
|
84
|
+
) -> AsyncPhase:
|
|
85
|
+
"""
|
|
86
|
+
Classify the phase of async request for routing purposes.
|
|
87
|
+
|
|
88
|
+
Returns:
|
|
89
|
+
AsyncPhase enum value representing the current phase:
|
|
90
|
+
- callback_completion: Callback has completed
|
|
91
|
+
- polling_continuation: Continuing an existing polling process
|
|
92
|
+
- initial_async: Initial async request setup
|
|
93
|
+
- sync: Not an async request
|
|
94
|
+
"""
|
|
95
|
+
if is_callback_completion(request_task):
|
|
96
|
+
return AsyncPhase.callback_completion
|
|
97
|
+
if is_polling_continuation(request_task):
|
|
98
|
+
return AsyncPhase.polling_continuation
|
|
99
|
+
if has_async_requests(query_config):
|
|
100
|
+
return AsyncPhase.initial_async
|
|
101
|
+
return AsyncPhase.sync
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def get_connection_config_from_task(
|
|
105
|
+
db: Session, request_task: RequestTask
|
|
106
|
+
) -> ConnectionConfig:
|
|
107
|
+
"""
|
|
108
|
+
Get ConnectionConfig from a RequestTask.
|
|
109
|
+
|
|
110
|
+
This utility function retrieves the connection configuration
|
|
111
|
+
associated with a request task by looking up the dataset configuration.
|
|
112
|
+
"""
|
|
113
|
+
dataset_config = DatasetConfig.filter(
|
|
114
|
+
db=db,
|
|
115
|
+
conditions=(DatasetConfig.fides_key == request_task.dataset_name),
|
|
116
|
+
).first()
|
|
117
|
+
if not dataset_config:
|
|
118
|
+
raise PrivacyRequestError(
|
|
119
|
+
f"DatasetConfig with fides_key {request_task.dataset_name} not found."
|
|
120
|
+
)
|
|
121
|
+
|
|
122
|
+
connection_config = ConnectionConfig.get(
|
|
123
|
+
db=db, object_id=dataset_config.connection_config_id
|
|
124
|
+
)
|
|
125
|
+
if not connection_config:
|
|
126
|
+
raise PrivacyRequestError(
|
|
127
|
+
f"ConnectionConfig with id {dataset_config.connection_config_id} not found."
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
return connection_config
|
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
|
+
from asyncio import sleep
|
|
4
|
+
from datetime import datetime
|
|
3
5
|
from typing import Any, Dict, List, Optional
|
|
4
6
|
|
|
5
7
|
import httpx
|
|
6
8
|
from httpx import AsyncClient, Client, HTTPStatusError, Request, RequestError, Timeout
|
|
7
9
|
from loguru import logger
|
|
8
10
|
|
|
11
|
+
from fides.api.common_exceptions import PrivacyRequestNotFound
|
|
9
12
|
from fides.api.schemas.privacy_request import (
|
|
10
13
|
PrivacyRequestCreate,
|
|
11
14
|
PrivacyRequestResponse,
|
|
@@ -13,11 +16,11 @@ from fides.api.schemas.privacy_request import (
|
|
|
13
16
|
)
|
|
14
17
|
from fides.api.schemas.redis_cache import Identity
|
|
15
18
|
from fides.api.schemas.user import UserLogin
|
|
16
|
-
from fides.api.service.privacy_request.request_service import poll_server_for_completion
|
|
17
19
|
from fides.api.util.collection_util import Row
|
|
18
20
|
from fides.api.util.errors import FidesError
|
|
19
21
|
from fides.api.util.wrappers import sync
|
|
20
22
|
from fides.common.api.v1 import urn_registry as urls
|
|
23
|
+
from fides.common.api.v1.urn_registry import PRIVACY_REQUESTS
|
|
21
24
|
|
|
22
25
|
COMPLETION_STATUSES = [
|
|
23
26
|
PrivacyRequestStatus.complete,
|
|
@@ -27,6 +30,65 @@ COMPLETION_STATUSES = [
|
|
|
27
30
|
]
|
|
28
31
|
|
|
29
32
|
|
|
33
|
+
def get_async_client() -> AsyncClient:
|
|
34
|
+
"""Return an async client used to make API requests"""
|
|
35
|
+
return AsyncClient()
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
async def poll_server_for_completion(
|
|
39
|
+
privacy_request_id: str,
|
|
40
|
+
server_url: str,
|
|
41
|
+
token: str,
|
|
42
|
+
*,
|
|
43
|
+
poll_interval_seconds: int = 30,
|
|
44
|
+
timeout_seconds: int = 1800, # 30 minutes
|
|
45
|
+
client: AsyncClient | None = None,
|
|
46
|
+
) -> PrivacyRequestResponse:
|
|
47
|
+
"""Poll a server for privacy request completion.
|
|
48
|
+
|
|
49
|
+
Requests will report complete with if they have a status of canceled, complete,
|
|
50
|
+
denied, or error. By default the polling will time out if not completed in 30
|
|
51
|
+
minutes, time can be overridden by setting the timeout_seconds.
|
|
52
|
+
"""
|
|
53
|
+
url = f"{server_url}{urls.V1_URL_PREFIX}{PRIVACY_REQUESTS}?request_id={privacy_request_id}"
|
|
54
|
+
start_time = datetime.now()
|
|
55
|
+
elapsed_time = 0.0
|
|
56
|
+
while elapsed_time < timeout_seconds:
|
|
57
|
+
if client:
|
|
58
|
+
response = await client.get(
|
|
59
|
+
url, headers={"Authorization": f"Bearer {token}"}
|
|
60
|
+
)
|
|
61
|
+
else:
|
|
62
|
+
async_client = get_async_client()
|
|
63
|
+
response = await async_client.get(
|
|
64
|
+
url, headers={"Authorization": f"Bearer {token}"}
|
|
65
|
+
)
|
|
66
|
+
response.raise_for_status()
|
|
67
|
+
|
|
68
|
+
# Privacy requests are returned paginated. Since this is searching for a specific
|
|
69
|
+
# privacy request there should only be one value present in items.
|
|
70
|
+
items = response.json()["items"]
|
|
71
|
+
if not items:
|
|
72
|
+
raise PrivacyRequestNotFound(
|
|
73
|
+
f"No privacy request found with id '{privacy_request_id}'"
|
|
74
|
+
)
|
|
75
|
+
status = PrivacyRequestResponse(**items[0])
|
|
76
|
+
if status.status and status.status in (
|
|
77
|
+
PrivacyRequestStatus.complete,
|
|
78
|
+
PrivacyRequestStatus.canceled,
|
|
79
|
+
PrivacyRequestStatus.error,
|
|
80
|
+
PrivacyRequestStatus.denied,
|
|
81
|
+
):
|
|
82
|
+
return status
|
|
83
|
+
|
|
84
|
+
await sleep(poll_interval_seconds)
|
|
85
|
+
time_delta = datetime.now() - start_time
|
|
86
|
+
elapsed_time = time_delta.seconds
|
|
87
|
+
raise TimeoutError(
|
|
88
|
+
f"Timeout of {timeout_seconds} seconds has been exceeded while waiting for privacy request {privacy_request_id}"
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
|
|
30
92
|
class FidesClient:
|
|
31
93
|
"""
|
|
32
94
|
A helper client to broker communications between Fides servers.
|
|
@@ -10,7 +10,6 @@ from uuid import uuid4
|
|
|
10
10
|
import pydash
|
|
11
11
|
from fideslang.models import FidesDatasetReference
|
|
12
12
|
from loguru import logger
|
|
13
|
-
from sqlalchemy.orm import Session
|
|
14
13
|
|
|
15
14
|
from fides.api.common_exceptions import FidesopsException
|
|
16
15
|
from fides.api.graph.execution import ExecutionNode
|
|
@@ -47,6 +46,7 @@ from fides.api.util.saas_util import (
|
|
|
47
46
|
ISO_8601_DATETIME,
|
|
48
47
|
MASKED_OBJECT_FIELDS,
|
|
49
48
|
PRIVACY_REQUEST_ID,
|
|
49
|
+
PRIVACY_REQUEST_OBJECT,
|
|
50
50
|
REPLY_TO,
|
|
51
51
|
REPLY_TO_TOKEN,
|
|
52
52
|
UUID,
|
|
@@ -140,7 +140,7 @@ class SaaSQueryConfig(QueryConfig[SaaSRequestParams]):
|
|
|
140
140
|
)
|
|
141
141
|
return request
|
|
142
142
|
|
|
143
|
-
def get_masking_request(self
|
|
143
|
+
def get_masking_request(self) -> Optional[SaaSRequest]:
|
|
144
144
|
"""
|
|
145
145
|
Returns a tuple of the preferred action and SaaSRequest to use for masking.
|
|
146
146
|
An update request is preferred, but we can use a gdpr delete endpoint or
|
|
@@ -212,6 +212,7 @@ class SaaSQueryConfig(QueryConfig[SaaSRequestParams]):
|
|
|
212
212
|
input_data: Dict[str, List[Any]],
|
|
213
213
|
policy: Optional[Policy],
|
|
214
214
|
read_request: SaaSRequest,
|
|
215
|
+
privacy_request: Optional[PrivacyRequest] = None,
|
|
215
216
|
) -> List[Tuple[SaaSRequestParams, Dict[str, Any]]]:
|
|
216
217
|
"""
|
|
217
218
|
Takes the identity and reference values from input_data and combines them
|
|
@@ -224,6 +225,10 @@ class SaaSQueryConfig(QueryConfig[SaaSRequestParams]):
|
|
|
224
225
|
self.current_request = read_request
|
|
225
226
|
|
|
226
227
|
request_params = []
|
|
228
|
+
|
|
229
|
+
if privacy_request:
|
|
230
|
+
input_data[PRIVACY_REQUEST_OBJECT] = [privacy_request.to_safe_dict()]
|
|
231
|
+
|
|
227
232
|
param_value_maps = self.generate_param_value_maps(input_data, read_request)
|
|
228
233
|
|
|
229
234
|
for param_value_map in param_value_maps:
|
|
@@ -343,6 +348,14 @@ class SaaSQueryConfig(QueryConfig[SaaSRequestParams]):
|
|
|
343
348
|
if self.privacy_request:
|
|
344
349
|
param_values[PRIVACY_REQUEST_ID] = self.privacy_request.id
|
|
345
350
|
|
|
351
|
+
privacy_request_object = input_data.get(PRIVACY_REQUEST_OBJECT)
|
|
352
|
+
if (
|
|
353
|
+
isinstance(privacy_request_object, list)
|
|
354
|
+
and len(privacy_request_object) > 0
|
|
355
|
+
and isinstance(privacy_request_object[0], dict)
|
|
356
|
+
):
|
|
357
|
+
param_values[PRIVACY_REQUEST_OBJECT] = privacy_request_object[0]
|
|
358
|
+
|
|
346
359
|
custom_privacy_request_fields = input_data.get(CUSTOM_PRIVACY_REQUEST_FIELDS)
|
|
347
360
|
if (
|
|
348
361
|
isinstance(custom_privacy_request_fields, list)
|
|
@@ -353,7 +366,8 @@ class SaaSQueryConfig(QueryConfig[SaaSRequestParams]):
|
|
|
353
366
|
]
|
|
354
367
|
|
|
355
368
|
param_values[UUID] = str(uuid4())
|
|
356
|
-
|
|
369
|
+
# Use full ISO-8601 timestamp including time component (UTC, seconds precision)
|
|
370
|
+
param_values[ISO_8601_DATETIME] = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
357
371
|
param_values[FIELD_LIST] = ",".join(
|
|
358
372
|
[
|
|
359
373
|
field.name
|
|
@@ -384,8 +398,7 @@ class SaaSQueryConfig(QueryConfig[SaaSRequestParams]):
|
|
|
384
398
|
The fields in the row are masked according to the policy and added to the request body
|
|
385
399
|
if specified by the body field of the masking request.
|
|
386
400
|
"""
|
|
387
|
-
|
|
388
|
-
current_request: SaaSRequest = self.get_masking_request(session) # type: ignore
|
|
401
|
+
current_request: SaaSRequest = self.get_masking_request() # type: ignore
|
|
389
402
|
param_values: Dict[str, Any] = self.generate_update_param_values(
|
|
390
403
|
row, policy, request, current_request
|
|
391
404
|
)
|
|
@@ -463,6 +476,8 @@ class SaaSQueryConfig(QueryConfig[SaaSRequestParams]):
|
|
|
463
476
|
if self.privacy_request:
|
|
464
477
|
param_values[PRIVACY_REQUEST_ID] = self.privacy_request.id
|
|
465
478
|
|
|
479
|
+
param_values[PRIVACY_REQUEST_OBJECT] = privacy_request.to_safe_dict()
|
|
480
|
+
|
|
466
481
|
param_values[CUSTOM_PRIVACY_REQUEST_FIELDS] = custom_privacy_request_fields
|
|
467
482
|
param_values[UUID] = str(uuid4())
|
|
468
483
|
param_values[ISO_8601_DATETIME] = datetime.now().strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
@@ -10,18 +10,16 @@ from requests import Response
|
|
|
10
10
|
from sqlalchemy.orm import Session
|
|
11
11
|
from starlette.status import HTTP_204_NO_CONTENT
|
|
12
12
|
|
|
13
|
+
from fides.api.api.deps import get_autoclose_db_session as get_db
|
|
13
14
|
from fides.api.common_exceptions import (
|
|
14
|
-
AwaitingAsyncTask,
|
|
15
15
|
FidesopsException,
|
|
16
16
|
PostProcessingException,
|
|
17
|
-
PrivacyRequestError,
|
|
18
17
|
SkippingConsentPropagation,
|
|
19
18
|
)
|
|
20
19
|
from fides.api.graph.execution import ExecutionNode
|
|
21
20
|
from fides.api.models.connectionconfig import ConnectionConfig, ConnectionTestStatus
|
|
22
21
|
from fides.api.models.policy import Policy
|
|
23
22
|
from fides.api.models.privacy_request import PrivacyRequest, RequestTask
|
|
24
|
-
from fides.api.models.privacy_request.request_task import AsyncTaskType
|
|
25
23
|
from fides.api.schemas.consentable_item import (
|
|
26
24
|
ConsentableItem,
|
|
27
25
|
build_consent_item_hierarchy,
|
|
@@ -39,6 +37,10 @@ from fides.api.schemas.saas.shared_schemas import (
|
|
|
39
37
|
ConsentPropagationStatus,
|
|
40
38
|
SaaSRequestParams,
|
|
41
39
|
)
|
|
40
|
+
from fides.api.service.async_dsr.strategies.async_dsr_strategy import AsyncDSRStrategy
|
|
41
|
+
from fides.api.service.async_dsr.strategies.async_dsr_strategy_factory import (
|
|
42
|
+
get_strategy,
|
|
43
|
+
)
|
|
42
44
|
from fides.api.service.connectors.base_connector import BaseConnector
|
|
43
45
|
from fides.api.service.connectors.query_configs.saas_query_config import SaaSQueryConfig
|
|
44
46
|
from fides.api.service.connectors.saas.authenticated_client import AuthenticatedClient
|
|
@@ -65,6 +67,7 @@ from fides.api.util.logger_context_utils import (
|
|
|
65
67
|
from fides.api.util.saas_util import (
|
|
66
68
|
ALL_OBJECT_FIELDS,
|
|
67
69
|
CUSTOM_PRIVACY_REQUEST_FIELDS,
|
|
70
|
+
PRIVACY_REQUEST_OBJECT,
|
|
68
71
|
assign_placeholders,
|
|
69
72
|
map_param_values,
|
|
70
73
|
)
|
|
@@ -216,19 +219,29 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
|
|
|
216
219
|
request_task: RequestTask,
|
|
217
220
|
input_data: Dict[str, List[Any]],
|
|
218
221
|
) -> List[Row]:
|
|
219
|
-
"""
|
|
222
|
+
"""
|
|
223
|
+
Retrieve data from SaaS APIs.
|
|
224
|
+
|
|
225
|
+
Handles sync requests directly and delegates async requests to external handlers.
|
|
226
|
+
"""
|
|
220
227
|
|
|
221
228
|
# pylint: disable=too-many-branches
|
|
222
229
|
self.set_privacy_request_state(privacy_request, node, request_task)
|
|
223
|
-
|
|
224
|
-
# If this is True, we assume we've received results from a third party
|
|
225
|
-
# asynchronously and we can proceed to the next node.
|
|
226
|
-
logger.info(
|
|
227
|
-
"Access callback succeeded for request task '{}'", request_task.id
|
|
228
|
-
)
|
|
229
|
-
return request_task.get_access_data()
|
|
230
|
+
|
|
230
231
|
query_config: SaaSQueryConfig = self.query_config(node)
|
|
231
232
|
|
|
233
|
+
# Delegate async requests
|
|
234
|
+
with get_db() as db:
|
|
235
|
+
if async_dsr_strategy := _get_async_dsr_strategy(
|
|
236
|
+
db, request_task, query_config, ActionType.access
|
|
237
|
+
):
|
|
238
|
+
return async_dsr_strategy.async_retrieve_data(
|
|
239
|
+
client=self.create_client(),
|
|
240
|
+
request_task_id=request_task.id,
|
|
241
|
+
query_config=query_config,
|
|
242
|
+
input_data=input_data,
|
|
243
|
+
)
|
|
244
|
+
|
|
232
245
|
# generate initial set of requests if read request is defined, otherwise raise an exception
|
|
233
246
|
# An endpoint can be defined with multiple 'read' requests if the data for a single
|
|
234
247
|
# collection can be accessed in multiple ways for example:
|
|
@@ -264,31 +277,11 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
|
|
|
264
277
|
if custom_privacy_request_fields:
|
|
265
278
|
input_data[CUSTOM_PRIVACY_REQUEST_FIELDS] = [custom_privacy_request_fields]
|
|
266
279
|
|
|
267
|
-
|
|
268
|
-
awaiting_async_processing: bool = False
|
|
280
|
+
input_data[PRIVACY_REQUEST_OBJECT] = [privacy_request.to_safe_dict()]
|
|
269
281
|
|
|
282
|
+
rows: List[Row] = []
|
|
270
283
|
for read_request in read_requests:
|
|
271
284
|
self.set_saas_request_state(read_request)
|
|
272
|
-
if (
|
|
273
|
-
read_request.async_config is not None
|
|
274
|
-
and request_task.id # Only supported in DSR 3.0
|
|
275
|
-
):
|
|
276
|
-
# Asynchronous read request detected. We will exit below and put the
|
|
277
|
-
# Request Task in an "awaiting_processing" status.
|
|
278
|
-
awaiting_async_processing = True
|
|
279
|
-
|
|
280
|
-
# Validate async strategy with proper enum value checking
|
|
281
|
-
strategy_value = read_request.async_config.strategy
|
|
282
|
-
valid_strategies = [task_type.value for task_type in AsyncTaskType]
|
|
283
|
-
|
|
284
|
-
if strategy_value not in valid_strategies:
|
|
285
|
-
raise PrivacyRequestError(
|
|
286
|
-
f"Invalid async type '{strategy_value}' for request task {request_task.id}. "
|
|
287
|
-
f"Valid types are: {valid_strategies}"
|
|
288
|
-
)
|
|
289
|
-
|
|
290
|
-
request_task.async_type = AsyncTaskType(strategy_value)
|
|
291
|
-
|
|
292
285
|
# check all the values specified by param_values are provided in input_data
|
|
293
286
|
if self._missing_dataset_reference_values(
|
|
294
287
|
input_data, read_request.param_values
|
|
@@ -310,7 +303,12 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
|
|
|
310
303
|
# if a path is provided, it means we want to generate HTTP requests from the config
|
|
311
304
|
if read_request.path:
|
|
312
305
|
prepared_requests: List[Tuple[SaaSRequestParams, Dict[str, Any]]] = (
|
|
313
|
-
query_config.generate_requests(
|
|
306
|
+
query_config.generate_requests(
|
|
307
|
+
input_data,
|
|
308
|
+
policy,
|
|
309
|
+
read_request,
|
|
310
|
+
privacy_request=privacy_request,
|
|
311
|
+
)
|
|
314
312
|
)
|
|
315
313
|
|
|
316
314
|
# Iterates through initial list of prepared requests and through subsequent
|
|
@@ -334,7 +332,7 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
|
|
|
334
332
|
# This allows us to build an output object even if we didn't generate and execute
|
|
335
333
|
# any HTTP requests. This is useful if we just want to select specific input_data
|
|
336
334
|
# values to provide as row data to the mask_data function
|
|
337
|
-
elif read_request.output:
|
|
335
|
+
elif not read_request.path and read_request.output:
|
|
338
336
|
rows.extend(
|
|
339
337
|
self._apply_output_template(
|
|
340
338
|
query_config.generate_param_value_maps(
|
|
@@ -345,17 +343,6 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
|
|
|
345
343
|
)
|
|
346
344
|
|
|
347
345
|
self.unset_connector_state()
|
|
348
|
-
if awaiting_async_processing:
|
|
349
|
-
# If a read request was marked to expect async results, original response data here is ignored.
|
|
350
|
-
# We'll instead use the data received in the callback URL later.
|
|
351
|
-
# However for polling async request we want to save the request data for ids that we will use on the pollings status
|
|
352
|
-
if request_task.async_type == AsyncTaskType.polling:
|
|
353
|
-
# Saving the request task access data to use it on the polling status request
|
|
354
|
-
# TODO: Consider if we want to clean up the rows. Currently this is the concern of the GraphTask.
|
|
355
|
-
request_task.access_data = rows
|
|
356
|
-
# Raising an AwaitingAsyncTask to put this task in an awaiting_processing state
|
|
357
|
-
raise AwaitingAsyncTask()
|
|
358
|
-
|
|
359
346
|
return rows
|
|
360
347
|
|
|
361
348
|
def _apply_output_template(
|
|
@@ -536,22 +523,28 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
|
|
|
536
523
|
rows: List[Row],
|
|
537
524
|
input_data: Optional[Dict[str, List[Any]]] = None,
|
|
538
525
|
) -> int:
|
|
539
|
-
"""
|
|
540
|
-
|
|
541
|
-
if request_task.callback_succeeded:
|
|
542
|
-
# If this is True, we assume the data was masked
|
|
543
|
-
# asynchronously and we can proceed to the next node.
|
|
544
|
-
logger.info(
|
|
545
|
-
"Masking callback succeeded for request task '{}'", request_task.id
|
|
546
|
-
)
|
|
547
|
-
# If we've received the callback for this node, return rows_masked directly
|
|
548
|
-
return request_task.rows_masked or 0
|
|
526
|
+
"""
|
|
527
|
+
Execute masking requests.
|
|
549
528
|
|
|
529
|
+
Handles synchronous requests directly and delegates async requests to external handlers.
|
|
530
|
+
"""
|
|
550
531
|
self.set_privacy_request_state(privacy_request, node, request_task)
|
|
532
|
+
|
|
551
533
|
query_config = self.query_config(node)
|
|
552
534
|
|
|
553
|
-
|
|
554
|
-
|
|
535
|
+
# Delegate async requests
|
|
536
|
+
with get_db() as db:
|
|
537
|
+
if async_dsr_strategy := _get_async_dsr_strategy(
|
|
538
|
+
db, request_task, query_config, ActionType.erasure
|
|
539
|
+
):
|
|
540
|
+
return async_dsr_strategy.async_mask_data(
|
|
541
|
+
client=self.create_client(),
|
|
542
|
+
request_task_id=request_task.id,
|
|
543
|
+
query_config=query_config,
|
|
544
|
+
rows=rows,
|
|
545
|
+
)
|
|
546
|
+
|
|
547
|
+
masking_request = query_config.get_masking_request()
|
|
555
548
|
rows_updated = 0
|
|
556
549
|
|
|
557
550
|
if not masking_request:
|
|
@@ -648,18 +641,6 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
|
|
|
648
641
|
)
|
|
649
642
|
|
|
650
643
|
self.unset_connector_state()
|
|
651
|
-
|
|
652
|
-
awaiting_async_callback: bool = bool(
|
|
653
|
-
masking_request.async_config
|
|
654
|
-
and masking_request.async_config.strategy == AsyncTaskType.callback.value
|
|
655
|
-
) and bool(
|
|
656
|
-
request_task.id
|
|
657
|
-
) # Only supported in DSR 3.0
|
|
658
|
-
if awaiting_async_callback:
|
|
659
|
-
# Asynchronous masking request detected in saas config.
|
|
660
|
-
# If the masking request was marked to expect async results, original responses are ignored
|
|
661
|
-
# and we raise an AwaitingAsyncTask to put this task in an awaiting_processing state.
|
|
662
|
-
raise AwaitingAsyncTask()
|
|
663
644
|
return rows_updated
|
|
664
645
|
|
|
665
646
|
@staticmethod
|
|
@@ -1112,3 +1093,38 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
|
|
|
1112
1093
|
return []
|
|
1113
1094
|
|
|
1114
1095
|
return consent_requests.opt_in if opt_in else consent_requests.opt_out # type: ignore
|
|
1096
|
+
|
|
1097
|
+
|
|
1098
|
+
def _get_async_dsr_strategy(
|
|
1099
|
+
session: Session,
|
|
1100
|
+
request_task: RequestTask,
|
|
1101
|
+
query_config: SaaSQueryConfig,
|
|
1102
|
+
action_type: ActionType,
|
|
1103
|
+
) -> Optional[AsyncDSRStrategy]:
|
|
1104
|
+
"""
|
|
1105
|
+
Returns the async DSR strategy if any of the read or masking requests have an async_config.
|
|
1106
|
+
"""
|
|
1107
|
+
|
|
1108
|
+
# Async processing is only supported for DSR 3.0.
|
|
1109
|
+
# A request task with an ID of None is an indicator that the request is not DSR 3.0.
|
|
1110
|
+
if request_task.id is None:
|
|
1111
|
+
return None
|
|
1112
|
+
|
|
1113
|
+
if action_type == ActionType.access:
|
|
1114
|
+
read_requests = query_config.get_read_requests_by_identity()
|
|
1115
|
+
for request in read_requests:
|
|
1116
|
+
if request.async_config is not None:
|
|
1117
|
+
return get_strategy(
|
|
1118
|
+
request.async_config.strategy,
|
|
1119
|
+
session,
|
|
1120
|
+
request.async_config.configuration,
|
|
1121
|
+
)
|
|
1122
|
+
elif action_type == ActionType.erasure:
|
|
1123
|
+
masking_request = query_config.get_masking_request()
|
|
1124
|
+
if masking_request is not None and masking_request.async_config is not None:
|
|
1125
|
+
return get_strategy(
|
|
1126
|
+
masking_request.async_config.strategy,
|
|
1127
|
+
session,
|
|
1128
|
+
masking_request.async_config.configuration,
|
|
1129
|
+
)
|
|
1130
|
+
return None
|
|
@@ -5,7 +5,7 @@ from typing import Any, Dict, Iterator, List, Optional, Tuple
|
|
|
5
5
|
from loguru import logger
|
|
6
6
|
|
|
7
7
|
from fides.api.models.attachment import Attachment, AttachmentType
|
|
8
|
-
from fides.api.schemas.storage.storage import StorageDetails
|
|
8
|
+
from fides.api.schemas.storage.storage import StorageDetails, StorageType
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@dataclass
|
|
@@ -84,12 +84,19 @@ def get_attachments_content(
|
|
|
84
84
|
continue
|
|
85
85
|
|
|
86
86
|
processed_count += 1
|
|
87
|
+
|
|
88
|
+
# Handle bucket_name differently for different storage types
|
|
89
|
+
bucket_name = None
|
|
90
|
+
if attachment.config.type in [StorageType.s3, StorageType.gcs]:
|
|
91
|
+
bucket_name = attachment.config.details[StorageDetails.BUCKET.value]
|
|
92
|
+
# For local storage, bucket_name is not needed
|
|
93
|
+
|
|
87
94
|
yield AttachmentData(
|
|
88
95
|
file_name=attachment.file_name,
|
|
89
96
|
file_size=size,
|
|
90
97
|
download_url=str(url) if url else None,
|
|
91
98
|
content_type=attachment.content_type,
|
|
92
|
-
bucket_name=
|
|
99
|
+
bucket_name=bucket_name or "", # Empty string for local storage
|
|
93
100
|
file_key=attachment.file_key,
|
|
94
101
|
storage_key=attachment.storage_key,
|
|
95
102
|
)
|