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.

Files changed (324) hide show
  1. {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/METADATA +1 -1
  2. {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/RECORD +262 -248
  3. fides/_version.py +3 -3
  4. fides/api/alembic/migrations/versions/4bfbeff34611_add_polling_status.py +35 -0
  5. fides/api/alembic/migrations/versions/7db29f9cd77b_create_new_sub_request_table.py +95 -0
  6. fides/api/alembic/migrations/versions/b97e92b038d2_add_digest_execution_model.py +117 -0
  7. fides/api/common_exceptions.py +4 -0
  8. fides/api/main.py +2 -2
  9. fides/api/models/attachment.py +1 -0
  10. fides/api/models/digest/__init__.py +2 -0
  11. fides/api/models/digest/digest_config.py +10 -1
  12. fides/api/models/digest/digest_execution.py +132 -0
  13. fides/api/models/event_audit.py +8 -0
  14. fides/api/models/privacy_request/privacy_request.py +1 -1
  15. fides/api/models/privacy_request/request_task.py +98 -1
  16. fides/api/models/worker_task.py +8 -0
  17. fides/api/schemas/saas/async_polling_configuration.py +81 -0
  18. fides/api/schemas/saas/saas_config.py +10 -3
  19. fides/api/schemas/saas/strategy_configuration.py +0 -12
  20. fides/api/service/async_dsr/handlers/__init__.py +0 -0
  21. fides/api/service/async_dsr/handlers/polling_attachment_handler.py +155 -0
  22. fides/api/service/async_dsr/handlers/polling_request_handler.py +88 -0
  23. fides/api/service/async_dsr/handlers/polling_response_handler.py +261 -0
  24. fides/api/service/async_dsr/handlers/polling_sub_request_handler.py +123 -0
  25. fides/api/service/async_dsr/strategies/__init__.py +0 -0
  26. fides/api/service/async_dsr/strategies/async_dsr_strategy.py +52 -0
  27. fides/api/service/async_dsr/strategies/async_dsr_strategy_callback.py +199 -0
  28. fides/api/service/async_dsr/strategies/async_dsr_strategy_factory.py +72 -0
  29. fides/api/service/async_dsr/strategies/async_dsr_strategy_polling.py +678 -0
  30. fides/api/service/async_dsr/utils.py +130 -0
  31. fides/api/service/connectors/fides/fides_client.py +63 -1
  32. fides/api/service/connectors/query_configs/saas_query_config.py +20 -5
  33. fides/api/service/connectors/saas_connector.py +86 -70
  34. fides/api/service/privacy_request/attachment_handling.py +9 -2
  35. fides/api/service/privacy_request/request_runner_service.py +9 -83
  36. fides/api/service/privacy_request/request_service.py +47 -74
  37. fides/api/service/saas_request/saas_request_override_factory.py +66 -1
  38. fides/api/task/execute_request_tasks.py +5 -2
  39. fides/api/task/filter_results.py +35 -2
  40. fides/api/task/graph_task.py +34 -2
  41. fides/api/util/saas_util.py +1 -0
  42. fides/config/execution_settings.py +7 -3
  43. fides/data/language/languages.yml +2 -0
  44. fides/ui-build/static/admin/404.html +1 -1
  45. fides/ui-build/static/admin/_next/static/chunks/1099-27b2d4e59a569b38.js +1 -0
  46. fides/ui-build/static/admin/_next/static/chunks/{1115-90baef2a89f361ad.js → 1115-8fb5000847f73ec7.js} +1 -1
  47. fides/ui-build/static/admin/_next/static/chunks/1437-fb699e9d69c3e325.js +1 -0
  48. fides/ui-build/static/admin/_next/static/chunks/155-3d03f101c662c054.js +1 -0
  49. fides/ui-build/static/admin/_next/static/chunks/{1817-1ad037b7d6d2f6d2.js → 1817-10b392e1dd9c4673.js} +1 -1
  50. fides/ui-build/static/admin/_next/static/chunks/{1975.78e719130cfe3fd6.js → 1975.50599b6774562644.js} +1 -1
  51. fides/ui-build/static/admin/_next/static/chunks/{2040-fdecc41a18e40bdc.js → 2040-01d5edb1802d3482.js} +1 -1
  52. fides/ui-build/static/admin/_next/static/chunks/2397-40506a386a3a469a.js +1 -0
  53. fides/ui-build/static/admin/_next/static/chunks/{2921-66f65496c3a09316.js → 2921-edfdffa353a611e4.js} +1 -1
  54. fides/ui-build/static/admin/_next/static/chunks/3377-4c129258b4c4ea28.js +1 -0
  55. fides/ui-build/static/admin/_next/static/chunks/{3696-90c8b336bbc46782.js → 3696-259be222ea12392a.js} +1 -1
  56. fides/ui-build/static/admin/_next/static/chunks/3700-42976bfaad3b91c9.js +1 -0
  57. fides/ui-build/static/admin/_next/static/chunks/3772-aa7beafe5df5e656.js +1 -0
  58. fides/ui-build/static/admin/_next/static/chunks/{3923-98bea73b618292aa.js → 3923-fa1d71afc7dc9e6e.js} +1 -1
  59. fides/ui-build/static/admin/_next/static/chunks/{401-ffe4e8436e1eceb9.js → 401-5270e3e23b08ab2b.js} +1 -1
  60. fides/ui-build/static/admin/_next/static/chunks/431-e01ee730c8ad9ece.js +1 -0
  61. fides/ui-build/static/admin/_next/static/chunks/4817-5f9b9c9bafe888f1.js +1 -0
  62. fides/ui-build/static/admin/_next/static/chunks/{5185-51eaa78e3ed6bfb7.js → 5185-325e5435a0c7dcb7.js} +1 -1
  63. fides/ui-build/static/admin/_next/static/chunks/5258-2d28b2c64acf5de3.js +1 -0
  64. fides/ui-build/static/admin/_next/static/chunks/{5279-12c9cbdc67ad7b14.js → 5279-21929b12c927b022.js} +1 -1
  65. fides/ui-build/static/admin/_next/static/chunks/549-c3b4c51f45a84a52.js +1 -0
  66. fides/ui-build/static/admin/_next/static/chunks/{5643-10a36584c399526c.js → 5643-7583c1f8dbd83273.js} +1 -1
  67. fides/ui-build/static/admin/_next/static/chunks/{5783-d119cb132abd8a91.js → 5783-55c0387508e50f3e.js} +1 -1
  68. fides/ui-build/static/admin/_next/static/chunks/{6277-182efc294d413f64.js → 6277-ca31d48a33202761.js} +1 -1
  69. fides/ui-build/static/admin/_next/static/chunks/6315-2d4e86a32fc40458.js +1 -0
  70. fides/ui-build/static/admin/_next/static/chunks/6344-ca66a6e10d128179.js +1 -0
  71. fides/ui-build/static/admin/_next/static/chunks/{6853-7004a8c420b1ca02.js → 6853-cb15625a713b3ef9.js} +1 -1
  72. fides/ui-build/static/admin/_next/static/chunks/{6954-4b24e1731c1cc3b3.js → 6954-08b59d28d7a2a43b.js} +1 -1
  73. fides/ui-build/static/admin/_next/static/chunks/7245-895bb7c6a6c797bc.js +1 -0
  74. fides/ui-build/static/admin/_next/static/chunks/{7476-d055aa931da47ac0.js → 7476-f25fce73eeb1f9c6.js} +1 -1
  75. fides/ui-build/static/admin/_next/static/chunks/7488-df17b592fbeaa1eb.js +1 -0
  76. fides/ui-build/static/admin/_next/static/chunks/{7630-d0d3a0fe3f95e971.js → 7630-71582de0e818e28f.js} +1 -1
  77. fides/ui-build/static/admin/_next/static/chunks/7773-98d34d188ae0a694.js +1 -0
  78. fides/ui-build/static/admin/_next/static/chunks/{796-02086581996a0548.js → 796-7944f684f8945506.js} +1 -1
  79. fides/ui-build/static/admin/_next/static/chunks/8011-56031d82d5428981.js +1 -0
  80. fides/ui-build/static/admin/_next/static/chunks/8373-7f940f5ac9c38b1f.js +1 -0
  81. fides/ui-build/static/admin/_next/static/chunks/9046-31b16a7e872c22be.js +1 -0
  82. fides/ui-build/static/admin/_next/static/chunks/9070-13f237db78da586d.js +1 -0
  83. fides/ui-build/static/admin/_next/static/chunks/9330-cea1bf40f5d27e53.js +1 -0
  84. fides/ui-build/static/admin/_next/static/chunks/{9676.b86ecbcfe5afd25d.js → 9676.1ea49d4b6e0541f2.js} +1 -1
  85. fides/ui-build/static/admin/_next/static/chunks/9682-2754256aeae141bb.js +1 -0
  86. fides/ui-build/static/admin/_next/static/chunks/{9826-ccedc28e978ca9e1.js → 9826-e71887e2c4283249.js} +1 -1
  87. fides/ui-build/static/admin/_next/static/chunks/9899-15530c468d5656a1.js +1 -0
  88. fides/ui-build/static/admin/_next/static/chunks/9965-54037b6c8f36d14b.js +1 -0
  89. fides/ui-build/static/admin/_next/static/chunks/pages/{404-2eb8aed4939f1142.js → 404-2014144a1a0fa64f.js} +1 -1
  90. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-c1c2f757b1f3da12.js → _app-9e869a44215709ed.js} +9 -9
  91. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-4f3ba02774f27795.js +1 -0
  92. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-2ca59996860a33c5.js → multiple-1c9cef80deccb15d.js} +1 -1
  93. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-4adeec3bcec05f7b.js +1 -0
  94. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-7a258b7ecd6da4b8.js → add-vendors-f7bdc2da53137ffd.js} +1 -1
  95. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-fb5017ff5fa54fcc.js → configure-a27b220fe76bdc8e.js} +1 -1
  96. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-e1e2fd704ac2d71d.js → [id]-542fd4a4322122f1.js} +1 -1
  97. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-92182be6603c2842.js → privacy-experience-4254abef7bb52edd.js} +1 -1
  98. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-5fc78b78a51c239c.js → [id]-d31d1c233e94dc1f.js} +1 -1
  99. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-b79bcb93b5f4c734.js → new-2ea057e6217993f9.js} +1 -1
  100. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-ab54b19609bff325.js → privacy-notices-8e76cbfaf71fdcb9.js} +1 -1
  101. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-069f4e3ee96ebf77.js → properties-eb557180eded0abd.js} +1 -1
  102. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-93730a4316c0d980.js +1 -0
  103. fides/ui-build/static/admin/_next/static/chunks/pages/{consent-d2bf72508c3cad55.js → consent-c64589e53338e59a.js} +1 -1
  104. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-2fa4b3a58f75f81d.js → [resourceUrn]-d3d1841bc8105e56.js} +1 -1
  105. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-8cd4d1d6ba000333.js +1 -0
  106. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-69b429a9d30ebaf1.js +1 -0
  107. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-5b31e3d7727b917a.js → [resourceUrn]-791c522ad1d9a2ce.js} +1 -1
  108. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources-8c7103ebf01d6e6a.js +1 -0
  109. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-a53ef0161235ee47.js +1 -0
  110. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-f85f4f8fcf1bfbdb.js +1 -0
  111. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/data-explorer-3619e454763dba09.js +1 -0
  112. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-ace848575e688200.js +1 -0
  113. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-53ca31c50c43007f.js +1 -0
  114. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-f87e4a0f664f4cde.js +1 -0
  115. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-844a8de0d1b506e2.js → [resourceUrn]-699762cb8a66237e.js} +1 -1
  116. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-11b07cf2d91b17ef.js → detection-d970d0b82db36c88.js} +1 -1
  117. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-5525cf287d4ab493.js → [resourceUrn]-a6343038a447699c.js} +1 -1
  118. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-ed4723e1b67d890e.js → discovery-ce82ba79f9bf825c.js} +1 -1
  119. fides/ui-build/static/admin/_next/static/chunks/pages/datamap-ae7a4c1c4eabc0d4.js +1 -0
  120. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-179e5d09ccff50c1.js +1 -0
  121. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-59466e5e238c59d0.js +1 -0
  122. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-36d90c8c39fb0d1c.js +1 -0
  123. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-db54d01fd8f6df50.js +1 -0
  124. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-55d312af5228e098.js +1 -0
  125. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-488beba62e832660.js +1 -0
  126. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-4aad5495f9bf81ce.js +1 -0
  127. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-496ec7ecca8259dc.js +1 -0
  128. fides/ui-build/static/admin/_next/static/chunks/pages/{index-b74d1e8608ae5b5d.js → index-8a2ba955d92d52ee.js} +1 -1
  129. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-4580f70eb41b6a7d.js +1 -0
  130. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-f69b04d3b4cf43b1.js +1 -0
  131. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-e8d2140787045acd.js → [id]-d6eed2dc5d27f625.js} +1 -1
  132. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-e3f93462a08251bf.js → add-template-c7b43fa365f4be10.js} +1 -1
  133. fides/ui-build/static/admin/_next/static/chunks/pages/{messaging-b5f7d6afdecd013d.js → messaging-c7ba755c2e0e2377.js} +1 -1
  134. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{ant-components-248ad9f65a872442.js → ant-components-f14bfd5890a0e939.js} +1 -1
  135. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{AntForm-aedb66a62042b10a.js → AntForm-e4274a4d5d23eea9.js} +1 -1
  136. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikAntFormItem-018df38b7cd77fdb.js → FormikAntFormItem-f5bce1ceb0502f04.js} +1 -1
  137. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikControlled-6ca9099d03aab817.js → FormikControlled-90b4ea9f9deca6e2.js} +1 -1
  138. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikField-0f2c90786ea005a4.js → FormikField-d6043ae8dae6ef7d.js} +1 -1
  139. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{forms-200b51a725f8b2d1.js → forms-520ba5ae02f47bda.js} +1 -1
  140. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{table-migration-29fb7b39f8962650.js → table-migration-b46f432b51421fae.js} +1 -1
  141. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-fe4ed3ad75151e36.js +1 -0
  142. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-de681c2d022c9e0d.js +1 -0
  143. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-8f577df28ebca869.js → configure-04ebf2fb6fc4358a.js} +1 -1
  144. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-cd8ba2eef9085377.js +1 -0
  145. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-57a75c7e9659271a.js → [id]-f75a407d78857ab3.js} +1 -1
  146. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-8964c2300206bc89.js → add-property-975ff605e1dbc09c.js} +1 -1
  147. fides/ui-build/static/admin/_next/static/chunks/pages/{properties-08472b2a6bf1d392.js → properties-e7fdf3a9a3e8c267.js} +1 -1
  148. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-764b6ce8e030d4a1.js +1 -0
  149. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/{[purpose_id]-f3e6e74e0efb005c.js → [purpose_id]-da78452b3c41b29e.js} +1 -1
  150. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{consent-4d658222ec800511.js → consent-6442e761ecb5c65a.js} +1 -1
  151. fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-ea9baf24de35d3b1.js +1 -0
  152. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-744f669431b84f71.js → domain-records-44d06e280990854d.js} +1 -1
  153. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domains-a3275554ffe8e640.js → domains-6f61d886aa6f5ce7.js} +1 -1
  154. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-604790638c656fbd.js → email-templates-11148b182370fd83.js} +1 -1
  155. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-be2a885150adc133.js → locations-33448bf0a1d53870.js} +1 -1
  156. fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers/{[key]-77239269acc2d31a.js → [key]-4a18d8135c0dbf2a.js} +1 -1
  157. fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers/{new-8bf1821722b082e9.js → new-41957281b8ec26b1.js} +1 -1
  158. fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers-776258bad0941a7d.js +1 -0
  159. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-3c86162afe9759df.js → organization-3c315036f1fc9f90.js} +1 -1
  160. fides/ui-build/static/admin/_next/static/chunks/pages/settings/privacy-requests-00917525c9245a90.js +1 -0
  161. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-4fe3b90747d885e5.js → regulations-5d924b2f1f926b88.js} +1 -1
  162. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-2deb6becece69d46.js → test-datasets-8067e12227210f48.js} +1 -1
  163. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-4d470bbf199a2f9c.js → [id]-1a902922759cae76.js} +1 -1
  164. fides/ui-build/static/admin/_next/static/chunks/pages/systems-277ea1f34c3714cf.js +1 -0
  165. fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-cecea5832cb1f3b0.js +1 -0
  166. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-98f737e735eaa0f0.js → [id]-726fbc0a34ffba1f.js} +1 -1
  167. fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-562624e5461083ec.js → user-management-df9b75ab01c1a2ea.js} +1 -1
  168. fides/ui-build/static/admin/_next/static/chunks/{webpack-2766492c5dbceb0a.js → webpack-118fb4723d13c14f.js} +1 -1
  169. fides/ui-build/static/admin/_next/static/css/372d6a236c84613f.css +1 -0
  170. fides/ui-build/static/admin/_next/static/css/f38242c11f7fea64.css +1 -0
  171. fides/ui-build/static/admin/_next/static/zmEQMSpOBih8kmA1t-EWO/_buildManifest.js +1 -0
  172. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  173. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  174. fides/ui-build/static/admin/add-systems.html +1 -1
  175. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  176. fides/ui-build/static/admin/consent/configure.html +1 -1
  177. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  178. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  179. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  180. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  181. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  182. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  183. fides/ui-build/static/admin/consent/properties.html +1 -1
  184. fides/ui-build/static/admin/consent/reporting.html +1 -1
  185. fides/ui-build/static/admin/consent.html +1 -1
  186. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  187. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  188. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  189. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  190. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  191. fides/ui-build/static/admin/data-catalog.html +1 -1
  192. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  193. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/data-explorer.html +1 -0
  194. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  195. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  196. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  197. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  198. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  199. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  200. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  201. fides/ui-build/static/admin/datamap.html +1 -1
  202. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  203. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  204. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  205. fides/ui-build/static/admin/dataset/new.html +1 -1
  206. fides/ui-build/static/admin/dataset.html +1 -1
  207. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  208. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  209. fides/ui-build/static/admin/datastore-connection.html +1 -1
  210. fides/ui-build/static/admin/index.html +1 -1
  211. fides/ui-build/static/admin/integrations/[id].html +1 -1
  212. fides/ui-build/static/admin/integrations.html +1 -1
  213. fides/ui-build/static/admin/login/[provider].html +1 -1
  214. fides/ui-build/static/admin/login.html +1 -1
  215. fides/ui-build/static/admin/messaging/[id].html +1 -1
  216. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  217. fides/ui-build/static/admin/messaging.html +1 -1
  218. fides/ui-build/static/admin/poc/ant-components.html +1 -1
  219. fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
  220. fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
  221. fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
  222. fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
  223. fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
  224. fides/ui-build/static/admin/poc/forms.html +1 -1
  225. fides/ui-build/static/admin/poc/table-migration.html +1 -1
  226. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  227. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  228. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  229. fides/ui-build/static/admin/privacy-requests.html +1 -1
  230. fides/ui-build/static/admin/properties/[id].html +1 -1
  231. fides/ui-build/static/admin/properties/add-property.html +1 -1
  232. fides/ui-build/static/admin/properties.html +1 -1
  233. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  234. fides/ui-build/static/admin/settings/about/alpha.html +1 -1
  235. fides/ui-build/static/admin/settings/about.html +1 -1
  236. fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
  237. fides/ui-build/static/admin/settings/consent.html +1 -1
  238. fides/ui-build/static/admin/settings/custom-fields/[id].html +1 -1
  239. fides/ui-build/static/admin/settings/custom-fields/new.html +1 -1
  240. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  241. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  242. fides/ui-build/static/admin/settings/domains.html +1 -1
  243. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  244. fides/ui-build/static/admin/settings/locations.html +1 -1
  245. fides/ui-build/static/admin/settings/messaging-providers/[key].html +1 -1
  246. fides/ui-build/static/admin/settings/messaging-providers/new.html +1 -1
  247. fides/ui-build/static/admin/settings/messaging-providers.html +1 -1
  248. fides/ui-build/static/admin/settings/organization.html +1 -1
  249. fides/ui-build/static/admin/settings/privacy-requests.html +1 -1
  250. fides/ui-build/static/admin/settings/regulations.html +1 -1
  251. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  252. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  253. fides/ui-build/static/admin/systems.html +1 -1
  254. fides/ui-build/static/admin/taxonomy.html +1 -1
  255. fides/ui-build/static/admin/user-management/new.html +1 -1
  256. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  257. fides/ui-build/static/admin/user-management.html +1 -1
  258. fides/api/service/async_dsr/async_dsr_service.py +0 -195
  259. fides/api/service/async_dsr/async_dsr_strategy.py +0 -5
  260. fides/api/service/async_dsr/async_dsr_strategy_callback.py +0 -16
  261. fides/api/service/async_dsr/async_dsr_strategy_factory.py +0 -63
  262. fides/api/service/async_dsr/async_dsr_strategy_polling.py +0 -94
  263. fides/ui-build/static/admin/_next/static/_IxwgneyQjdSaZFEF3Tqu/_buildManifest.js +0 -1
  264. fides/ui-build/static/admin/_next/static/chunks/155-b4337d0826d5addc.js +0 -1
  265. fides/ui-build/static/admin/_next/static/chunks/3585-f728d32fda6f1ac1.js +0 -1
  266. fides/ui-build/static/admin/_next/static/chunks/3855-ed226b8a8050bd40.js +0 -1
  267. fides/ui-build/static/admin/_next/static/chunks/3872-04d3afbfa41a7782.js +0 -1
  268. fides/ui-build/static/admin/_next/static/chunks/409-5c3d31163028339f.js +0 -1
  269. fides/ui-build/static/admin/_next/static/chunks/431-78bf05f35d7eec4f.js +0 -1
  270. fides/ui-build/static/admin/_next/static/chunks/4558-8305aee48def1dcd.js +0 -1
  271. fides/ui-build/static/admin/_next/static/chunks/4608-0c6ef78e30a51f84.js +0 -1
  272. fides/ui-build/static/admin/_next/static/chunks/4718-3a412bdb90add82f.js +0 -1
  273. fides/ui-build/static/admin/_next/static/chunks/502-0d9f4ac29ef34a1c.js +0 -1
  274. fides/ui-build/static/admin/_next/static/chunks/504-88caa30c03374e9b.js +0 -1
  275. fides/ui-build/static/admin/_next/static/chunks/5309-3b6cf0cc9d0c6a83.js +0 -1
  276. fides/ui-build/static/admin/_next/static/chunks/5574-c31ea831371610d5.js +0 -1
  277. fides/ui-build/static/admin/_next/static/chunks/6882-dbe0a25dcf1a8ee0.js +0 -1
  278. fides/ui-build/static/admin/_next/static/chunks/7045-14e955890f1147e4.js +0 -1
  279. fides/ui-build/static/admin/_next/static/chunks/7079-50571e9f3269d74d.js +0 -1
  280. fides/ui-build/static/admin/_next/static/chunks/7158-04745cc8d684b2e7.js +0 -1
  281. fides/ui-build/static/admin/_next/static/chunks/7218-e2983b96b95e33b4.js +0 -1
  282. fides/ui-build/static/admin/_next/static/chunks/7725-f2a7be705b75dcc3.js +0 -1
  283. fides/ui-build/static/admin/_next/static/chunks/7929-0fd0d4948bc8d70e.js +0 -1
  284. fides/ui-build/static/admin/_next/static/chunks/8002-ed832921ad190832.js +0 -1
  285. fides/ui-build/static/admin/_next/static/chunks/9046-b6616ba7b59d947e.js +0 -1
  286. fides/ui-build/static/admin/_next/static/chunks/9226-4a7027057f55ca2a.js +0 -1
  287. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-4ec03eed67572861.js +0 -1
  288. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-19214babd1f219e3.js +0 -1
  289. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-c1a3caf3c286bf5d.js +0 -1
  290. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-4a1af12d2d7cd660.js +0 -1
  291. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-99573a1ee3ef8f4c.js +0 -1
  292. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources-6e429b7511028d60.js +0 -1
  293. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-b7326c51d88cc2cc.js +0 -1
  294. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-5b57f9132426fe52.js +0 -1
  295. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-0d512528b498d75c.js +0 -1
  296. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-040813022f0890c9.js +0 -1
  297. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-a28cc0e23bbe4fc8.js +0 -1
  298. fides/ui-build/static/admin/_next/static/chunks/pages/datamap-7d22222608ec3aac.js +0 -1
  299. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-0abd30eada811b5b.js +0 -1
  300. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-007965429368d9a3.js +0 -1
  301. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-60a4a9eb4aab4c11.js +0 -1
  302. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-d514cd4ec62e3b03.js +0 -1
  303. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-0e3a6ac4797ffbbb.js +0 -1
  304. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-816e02b6cbe4a684.js +0 -1
  305. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-b6838162200141b3.js +0 -1
  306. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-223c2d1ded51bfb1.js +0 -1
  307. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-153eb88ab4e7dc6d.js +0 -1
  308. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-331544e9b85c4ac2.js +0 -1
  309. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-7dac2302f573f5ee.js +0 -1
  310. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-479890582973deaf.js +0 -1
  311. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-7af00f72cf694077.js +0 -1
  312. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-f7753e9effae3816.js +0 -1
  313. fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-2fcd95c41e578d57.js +0 -1
  314. fides/ui-build/static/admin/_next/static/chunks/pages/settings/messaging-providers-8d92be437793c96f.js +0 -1
  315. fides/ui-build/static/admin/_next/static/chunks/pages/settings/privacy-requests-97221067330c0c27.js +0 -1
  316. fides/ui-build/static/admin/_next/static/chunks/pages/systems-6c91bdea40875227.js +0 -1
  317. fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-3059aba38adefa56.js +0 -1
  318. fides/ui-build/static/admin/_next/static/css/073713cd1eddda79.css +0 -1
  319. fides/ui-build/static/admin/_next/static/css/295d729ea1b11885.css +0 -1
  320. {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/WHEEL +0 -0
  321. {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/entry_points.txt +0 -0
  322. {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/licenses/LICENSE +0 -0
  323. {ethyca_fides-2.71.1b1.dist-info → ethyca_fides-2.71.2b0.dist-info}/top_level.txt +0 -0
  324. /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, db: Session) -> Optional[SaaSRequest]:
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
- param_values[ISO_8601_DATETIME] = datetime.now().date().isoformat()
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
- session = Session.object_session(request)
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
- """Retrieve data from SaaS APIs"""
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
- if request_task.callback_succeeded:
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
- rows: List[Row] = []
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(input_data, policy, read_request)
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
- """Execute a masking request. Return the number of rows that have been updated."""
540
- self.set_privacy_request_state(privacy_request, node, request_task)
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
- session = Session.object_session(privacy_request)
554
- masking_request = query_config.get_masking_request(session)
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=attachment.config.details[StorageDetails.BUCKET.value],
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
  )