ethyca-fides 2.57.1rc0__py2.py3-none-any.whl → 2.58.0__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.
Files changed (299) hide show
  1. {ethyca_fides-2.57.1rc0.dist-info → ethyca_fides-2.58.0.dist-info}/METADATA +1 -1
  2. {ethyca_fides-2.57.1rc0.dist-info → ethyca_fides-2.58.0.dist-info}/RECORD +245 -230
  3. fides/_version.py +3 -3
  4. fides/api/alembic/migrations/versions/1d2f04ac19f2_add_page_column_to_asset_table.py +49 -0
  5. fides/api/alembic/migrations/versions/7c3fbee90c78_add_user_assigned_data_uses_and_system_.py +54 -0
  6. fides/api/alembic/migrations/versions/9a1eacd2666b_add_description_column_to_asset.py +25 -0
  7. fides/api/api/v1/endpoints/config_endpoints.py +4 -2
  8. fides/api/api/v1/endpoints/generic_overrides.py +48 -6
  9. fides/api/graph/traversal.py +8 -0
  10. fides/api/models/asset.py +37 -18
  11. fides/api/models/attachment.py +11 -13
  12. fides/api/models/comment.py +17 -17
  13. fides/api/models/connectionconfig.py +1 -1
  14. fides/api/models/detection_discovery.py +12 -0
  15. fides/api/models/location_regulation_selections.py +1 -0
  16. fides/api/models/privacy_request/__init__.py +44 -0
  17. fides/api/models/privacy_request/consent.py +155 -0
  18. fides/api/models/privacy_request/execution_log.py +108 -0
  19. fides/api/models/{privacy_request.py → privacy_request/privacy_request.py} +82 -691
  20. fides/api/models/privacy_request/provided_identity.py +149 -0
  21. fides/api/models/privacy_request/request_task.py +284 -0
  22. fides/api/models/privacy_request/webhook.py +94 -0
  23. fides/api/models/sql_models.py +28 -5
  24. fides/api/oauth/jwt.py +18 -0
  25. fides/api/oauth/utils.py +11 -11
  26. fides/api/schemas/connection_configuration/connection_secrets_datahub.py +2 -4
  27. fides/api/schemas/dataset.py +22 -2
  28. fides/api/schemas/saas/strategy_configuration.py +1 -0
  29. fides/api/service/pagination/pagination_strategy_cursor.py +15 -1
  30. fides/api/service/pagination/pagination_strategy_link.py +1 -1
  31. fides/api/service/storage/s3.py +193 -0
  32. fides/api/service/storage/util.py +10 -0
  33. fides/api/tasks/storage.py +12 -111
  34. fides/config/__init__.py +1 -1
  35. fides/data/language/languages.yml +2 -0
  36. fides/data/location/locations.yml +244 -1
  37. fides/ui-build/static/admin/404.html +1 -1
  38. fides/ui-build/static/admin/_next/static/83Gi0kdCvIdkdE1Kf6DS1/_buildManifest.js +1 -0
  39. fides/ui-build/static/admin/_next/static/83Gi0kdCvIdkdE1Kf6DS1/_ssgManifest.js +1 -0
  40. fides/ui-build/static/admin/_next/static/chunks/1100-053fc6b76c65a00f.js +1 -0
  41. fides/ui-build/static/admin/_next/static/chunks/{1150-73440d7b319558e8.js → 1150-035a721a04f4451e.js} +1 -1
  42. fides/ui-build/static/admin/_next/static/chunks/1376-5cea5ef9362215e8.js +1 -0
  43. fides/ui-build/static/admin/_next/static/chunks/{2397-7177ecf4ebe68feb.js → 2397-ee53235fb21b5e97.js} +1 -1
  44. fides/ui-build/static/admin/_next/static/chunks/{255-bf1797f78249d090.js → 255-7db55b0e3a0f9dea.js} +1 -1
  45. fides/ui-build/static/admin/_next/static/chunks/2fbcc6de-a6c61724c327e9fa.js +8 -0
  46. fides/ui-build/static/admin/_next/static/chunks/{3086-be6b52546c3efc90.js → 3086-b5054ec2c75700b9.js} +1 -1
  47. fides/ui-build/static/admin/_next/static/chunks/3412-7ec8751b8182e1bf.js +1 -0
  48. fides/ui-build/static/admin/_next/static/chunks/355-8a77c9a1cd027f2e.js +1 -0
  49. fides/ui-build/static/admin/_next/static/chunks/3615-5e2d062d684b8fa1.js +1 -0
  50. fides/ui-build/static/admin/_next/static/chunks/{3855-5c7b11871f59e0e0.js → 3855-b6b7865dedd7bc2a.js} +1 -1
  51. fides/ui-build/static/admin/_next/static/chunks/{3872-f3d5054bdc584eaa.js → 3872-4e053c20d546f027.js} +1 -1
  52. fides/ui-build/static/admin/_next/static/chunks/4060-8d165e1236ea521a.js +1 -0
  53. fides/ui-build/static/admin/_next/static/chunks/4450-36234280bee624ff.js +1 -0
  54. fides/ui-build/static/admin/_next/static/chunks/4481-aab99ff80f707473.js +1 -0
  55. fides/ui-build/static/admin/_next/static/chunks/4723-0a3c5e2ce143a7d0.js +1 -0
  56. fides/ui-build/static/admin/_next/static/chunks/{5258-3a650be9142cf914.js → 5258-0658dc2274df6832.js} +1 -1
  57. fides/ui-build/static/admin/_next/static/chunks/5277-e8a036319456127f.js +1 -0
  58. fides/ui-build/static/admin/_next/static/chunks/{5480-f5bec5e881f72f8d.js → 5480-f49696df5e8ae500.js} +1 -1
  59. fides/ui-build/static/admin/_next/static/chunks/{5487-d96e1abc93f92631.js → 5487-3ad50d21cdbc9209.js} +1 -1
  60. fides/ui-build/static/admin/_next/static/chunks/570-c99f07161bd339cd.js +1 -0
  61. fides/ui-build/static/admin/_next/static/chunks/{5826-16e497af363a0cbc.js → 5826-e5dcb4e68cfe6289.js} +1 -1
  62. fides/ui-build/static/admin/_next/static/chunks/5973-52aee296edc44f7e.js +1 -0
  63. fides/ui-build/static/admin/_next/static/chunks/6060-cb1ab5be7067bf7b.js +4 -0
  64. fides/ui-build/static/admin/_next/static/chunks/{6315-dee79f6861c94d2d.js → 6315-fa1519cdf080f42d.js} +1 -1
  65. fides/ui-build/static/admin/_next/static/chunks/{6372-f1b54f3cb4888660.js → 6372-ca9c12ac8902365b.js} +1 -1
  66. fides/ui-build/static/admin/_next/static/chunks/6527-0eed08abe252a918.js +1 -0
  67. fides/ui-build/static/admin/_next/static/chunks/678d4732-50255cc09048e643.js +2 -0
  68. fides/ui-build/static/admin/_next/static/chunks/{6853-cacea421af3bfc26.js → 6853-8941824350c3c1a8.js} +1 -1
  69. fides/ui-build/static/admin/_next/static/chunks/6954-3b887fb444f9228c.js +1 -0
  70. fides/ui-build/static/admin/_next/static/chunks/{7088.0e7c92a7cbb57562.js → 7088.eb76fca286e5f2e6.js} +1 -1
  71. fides/ui-build/static/admin/_next/static/chunks/7453-39761c38da31257e.js +1 -0
  72. fides/ui-build/static/admin/_next/static/chunks/{7751-25e0c1307988ffd7.js → 7751-a8f31c062d4cb09d.js} +1 -1
  73. fides/ui-build/static/admin/_next/static/chunks/{79-ba88d0cf4c65aaa2.js → 79-f9b948ebb186900f.js} +1 -1
  74. fides/ui-build/static/admin/_next/static/chunks/7980-4bd08957448dea32.js +1 -0
  75. fides/ui-build/static/admin/_next/static/chunks/7c79804f.7a7112aece470725.js +1 -0
  76. fides/ui-build/static/admin/_next/static/chunks/{8433-969280d321d1c3a2.js → 8433-b3008ecaf9834e7f.js} +1 -1
  77. fides/ui-build/static/admin/_next/static/chunks/{8499-07507004e8275df2.js → 8499-43606100edf42fdf.js} +1 -1
  78. fides/ui-build/static/admin/_next/static/chunks/8702-d1c8296f9f6afc10.js +1 -0
  79. fides/ui-build/static/admin/_next/static/chunks/{5908-532dfbc9d930f635.js → 9014-eeae6f581158e645.js} +1 -1
  80. fides/ui-build/static/admin/_next/static/chunks/{9046-80f1ea44f89fe32c.js → 9046-04bd7becea207cb1.js} +1 -1
  81. fides/ui-build/static/admin/_next/static/chunks/905-8ab919e7b274ed50.js +8 -0
  82. fides/ui-build/static/admin/_next/static/chunks/9187-851756440f79cd75.js +1 -0
  83. fides/ui-build/static/admin/_next/static/chunks/9282-2bfbdca45e84e810.js +1 -0
  84. fides/ui-build/static/admin/_next/static/chunks/9327-2cba327d10586683.js +1 -0
  85. fides/ui-build/static/admin/_next/static/chunks/{9392.97b2e3327dceb7c9.js → 9392.da35a8e778812d91.js} +1 -1
  86. fides/ui-build/static/admin/_next/static/chunks/9676.f297a1347ac09c56.js +1 -0
  87. fides/ui-build/static/admin/_next/static/chunks/9767-1a23925d2cb27b51.js +1 -0
  88. fides/ui-build/static/admin/_next/static/chunks/{9999-f2e40d5b13343220.js → 9999-637e0e5341f15f4a.js} +1 -1
  89. fides/ui-build/static/admin/_next/static/chunks/e3251fe7-5777b5d778e6fffa.js +1 -0
  90. fides/ui-build/static/admin/_next/static/chunks/main-24f422f93845a596.js +1 -0
  91. fides/ui-build/static/admin/_next/static/chunks/{main-app-2650f704701c6a7b.js → main-app-94a0711202e08b15.js} +1 -1
  92. fides/ui-build/static/admin/_next/static/chunks/pages/{404-1087258931760074.js → 404-b202c0d8f6fc75c3.js} +1 -1
  93. fides/ui-build/static/admin/_next/static/chunks/pages/_app-fc89ce7bed454c84.js +923 -0
  94. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-d7f60624cbc12217.js → manual-9acaab973dfe86e2.js} +1 -1
  95. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-18b0b521255289a3.js → multiple-ba975134a85588f8.js} +1 -1
  96. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-d258f0c25fa020bf.js +1 -0
  97. fides/ui-build/static/admin/_next/static/chunks/pages/{ant-poc-b3b4d0a98450ffd1.js → ant-poc-b9932971a479f3a7.js} +1 -1
  98. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-64f83e9a2b777bf3.js → add-vendors-b34e5324461d0c87.js} +1 -1
  99. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-723cc3d4f5740ea6.js +1 -0
  100. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-443e6dd191ce5588.js → [id]-fb75fa0aea77678d.js} +1 -1
  101. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{new-36162d5bea29dcc2.js → new-a9d9402c219d13e5.js} +1 -1
  102. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-35e9df60b21e21a6.js → privacy-experience-c946b33b0322b8ad.js} +1 -1
  103. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-2d651499c07d12d9.js → [id]-72251b48e2e03a1e.js} +1 -1
  104. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-36e57d2f2446be82.js → new-9611dd42856d6062.js} +1 -1
  105. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-da37afbe5ec81339.js → privacy-notices-ea57f9d6ad17e957.js} +1 -1
  106. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-c57b209feef7c2da.js → properties-e5748812ba055a56.js} +1 -1
  107. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-788cf0e34829af46.js +1 -0
  108. fides/ui-build/static/admin/_next/static/chunks/pages/{consent-24bef021ee71e36c.js → consent-39d65f13cc8f1cf8.js} +1 -1
  109. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-6cbd79481199812d.js → [resourceUrn]-ac033a16f043e6f9.js} +1 -1
  110. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-46b9790da2fec05a.js → [projectUrn]-a29850536c85d4b8.js} +1 -1
  111. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{projects-1f965b9c496071d1.js → projects-c44ce244122e96d5.js} +1 -1
  112. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-e7833c1c606081a9.js → [resourceUrn]-71e26d262afcaea5.js} +1 -1
  113. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{resources-bed368d048ea6883.js → resources-305555b74c357bf2.js} +1 -1
  114. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-900004e402c31797.js +1 -0
  115. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-b66831fdafcdf67c.js +1 -0
  116. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-5f9ef1f99818117c.js +1 -0
  117. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-d001337d1bb73bd1.js +1 -0
  118. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{activity-1d7936f05d23097f.js → activity-11b3ce9f61d9bfe9.js} +1 -1
  119. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-68122dbf449a11b4.js → [resourceUrn]-054ca46a782e99a5.js} +1 -1
  120. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-0ceaf3c555e84714.js → detection-b75dd3e4306ac18e.js} +1 -1
  121. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-22c27fe0f898ad2a.js → [resourceUrn]-1da20aeb6fc995e4.js} +1 -1
  122. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-8f2b102e19b0b8f2.js → discovery-cad50b0cc6d1050c.js} +1 -1
  123. fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-9cd0c40bef77b120.js → datamap-8cb714cdd44ac40e.js} +1 -1
  124. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-d79551d4c64c398c.js +1 -0
  125. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-7e5df4a0de7540bb.js +1 -0
  126. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{[datasetId]-e14c1c07658f8a10.js → [datasetId]-6ba18f92ba561114.js} +1 -1
  127. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-803c1b577ab17ae3.js +1 -0
  128. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-fa743ddc7f89d76b.js +1 -0
  129. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-0616437e1a82d3ed.js → [id]-bbe1ca2793798e6b.js} +1 -1
  130. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-f8218440494e8532.js → new-abc17fef69cd951b.js} +1 -1
  131. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-a78a73b65929853a.js +1 -0
  132. fides/ui-build/static/admin/_next/static/chunks/pages/fides-js-docs-80b241bf6cddb72e.js +1 -0
  133. fides/ui-build/static/admin/_next/static/chunks/pages/{index-94e6d589c4edf360.js → index-bfaacdb55a5a6c9f.js} +1 -1
  134. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-d4329043219fed9b.js +1 -0
  135. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-ef8000d7388dc915.js +1 -0
  136. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-6b032de0a6c2c400.js → [id]-ad02e019b2467958.js} +1 -1
  137. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-c0d6ae68ff7979c6.js → add-template-f9693cb6a0b7ded8.js} +1 -1
  138. fides/ui-build/static/admin/_next/static/chunks/pages/messaging-1e60754abec1ee6b.js +1 -0
  139. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{[id]-bbe5854b7d19b7e9.js → [id]-fe765154315782cf.js} +1 -1
  140. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-f5f7a8069909ef24.js +1 -0
  141. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-9f7eaad05e5b9292.js +1 -0
  142. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-4bad69cd42c9722c.js → configure-2987edc77388e85a.js} +1 -1
  143. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-d85c0d16ba09ba35.js +1 -0
  144. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-b4c808a8a0287d11.js → [id]-94e2faa73dd6a3e6.js} +1 -1
  145. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-5a701477b006a63b.js → add-property-630a6a3dd6502ba6.js} +1 -1
  146. fides/ui-build/static/admin/_next/static/chunks/pages/{properties-9a1899dfe052023e.js → properties-20ca2f963906674b.js} +1 -1
  147. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-afedc48ef4e7f858.js +1 -0
  148. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{about-d073be113e9ca7b0.js → about-a49d0f84cf0cf05e.js} +1 -1
  149. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-89524101b7279f6e.js +1 -0
  150. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{custom-fields-744e7bbc200557e7.js → custom-fields-52d030b1db2ca1b9.js} +1 -1
  151. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-c5cd5fb578de9515.js → domain-records-fa42d8f18df44927.js} +1 -1
  152. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-24cba38685dc872c.js +1 -0
  153. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-39c7ae3602ac69b2.js → email-templates-6fd6071e2009b8f2.js} +1 -1
  154. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-45e33ba111f8f8b0.js → locations-66c757325cb58467.js} +1 -1
  155. fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-a08693d0d1e10bc8.js +1 -0
  156. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-94975aeab348528e.js → regulations-c6c239996cfa6ae8.js} +1 -1
  157. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-151571cff4e85894.js +1 -0
  158. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-82d9af34546adaa2.js → [id]-4f5a28226575c976.js} +1 -1
  159. fides/ui-build/static/admin/_next/static/chunks/pages/{systems-c320df35d51dc537.js → systems-abd68fc5ddde5482.js} +1 -1
  160. fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-181ea5b0ac975239.js → taxonomy-16b4d75c49276add.js} +1 -1
  161. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-622e16a17a11c096.js → [id]-78eaf933f755bfe8.js} +1 -1
  162. fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-aa872b21bb835d34.js → user-management-6c9ad62479a7d03e.js} +1 -1
  163. fides/ui-build/static/admin/_next/static/chunks/{webpack-4df2ba5ee2d40f0a.js → webpack-2c7ccac5843c4d8e.js} +1 -1
  164. fides/ui-build/static/admin/_next/static/css/113d823fe71f6af0.css +1 -0
  165. fides/ui-build/static/admin/_next/static/css/ab65b8cc3144bfc8.css +1 -0
  166. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  167. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  168. fides/ui-build/static/admin/add-systems.html +1 -1
  169. fides/ui-build/static/admin/ant-poc.html +1 -1
  170. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  171. fides/ui-build/static/admin/consent/configure.html +1 -1
  172. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  173. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  174. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  175. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  176. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  177. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  178. fides/ui-build/static/admin/consent/properties.html +1 -1
  179. fides/ui-build/static/admin/consent/reporting.html +1 -1
  180. fides/ui-build/static/admin/consent.html +1 -1
  181. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  182. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  183. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  184. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  185. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  186. fides/ui-build/static/admin/data-catalog.html +1 -1
  187. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  188. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  189. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  190. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  191. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  192. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  193. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  194. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  195. fides/ui-build/static/admin/datamap.html +1 -1
  196. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  197. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  198. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  199. fides/ui-build/static/admin/dataset/new.html +1 -1
  200. fides/ui-build/static/admin/dataset.html +1 -1
  201. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  202. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  203. fides/ui-build/static/admin/datastore-connection.html +1 -1
  204. fides/ui-build/static/admin/index.html +1 -1
  205. fides/ui-build/static/admin/integrations/[id].html +1 -1
  206. fides/ui-build/static/admin/integrations.html +1 -1
  207. fides/ui-build/static/admin/lib/fides-ext-gpp.js +1 -1
  208. fides/ui-build/static/admin/lib/fides-headless.js +1 -1
  209. fides/ui-build/static/admin/lib/fides-tcf.js +3 -3
  210. fides/ui-build/static/admin/lib/fides.js +2 -2
  211. fides/ui-build/static/admin/login/[provider].html +1 -1
  212. fides/ui-build/static/admin/login.html +1 -1
  213. fides/ui-build/static/admin/messaging/[id].html +1 -1
  214. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  215. fides/ui-build/static/admin/messaging.html +1 -1
  216. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  217. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  218. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  219. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  220. fides/ui-build/static/admin/privacy-requests.html +1 -1
  221. fides/ui-build/static/admin/properties/[id].html +1 -1
  222. fides/ui-build/static/admin/properties/add-property.html +1 -1
  223. fides/ui-build/static/admin/properties.html +1 -1
  224. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  225. fides/ui-build/static/admin/settings/about.html +1 -1
  226. fides/ui-build/static/admin/settings/consent.html +1 -1
  227. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  228. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  229. fides/ui-build/static/admin/settings/domains.html +1 -1
  230. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  231. fides/ui-build/static/admin/settings/locations.html +1 -1
  232. fides/ui-build/static/admin/settings/organization.html +1 -1
  233. fides/ui-build/static/admin/settings/regulations.html +1 -1
  234. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  235. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  236. fides/ui-build/static/admin/systems.html +1 -1
  237. fides/ui-build/static/admin/taxonomy.html +1 -1
  238. fides/ui-build/static/admin/user-management/new.html +1 -1
  239. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  240. fides/ui-build/static/admin/user-management.html +1 -1
  241. fides/ui-build/static/admin/_next/static/chunks/1995-0e4fc4f7b44ed72b.js +0 -1
  242. fides/ui-build/static/admin/_next/static/chunks/2780-8328de94968d05e4.js +0 -4
  243. fides/ui-build/static/admin/_next/static/chunks/3005-373de16453ed7eea.js +0 -1
  244. fides/ui-build/static/admin/_next/static/chunks/3320-87c75df57a47487e.js +0 -1
  245. fides/ui-build/static/admin/_next/static/chunks/3627-fb83adac32c128e6.js +0 -1
  246. fides/ui-build/static/admin/_next/static/chunks/3662-420d9807c30008ab.js +0 -1
  247. fides/ui-build/static/admin/_next/static/chunks/3949-9888699e2ac564c4.js +0 -1
  248. fides/ui-build/static/admin/_next/static/chunks/3967-845c902667e47c4f.js +0 -1
  249. fides/ui-build/static/admin/_next/static/chunks/3e38ba78-4487e45fd4ed2479.js +0 -2
  250. fides/ui-build/static/admin/_next/static/chunks/4481-ca8d2c75d634b6bc.js +0 -1
  251. fides/ui-build/static/admin/_next/static/chunks/4723-81d28e5be5c7b6d7.js +0 -1
  252. fides/ui-build/static/admin/_next/static/chunks/4833-a85bd5d25ebc40c4.js +0 -1
  253. fides/ui-build/static/admin/_next/static/chunks/5246-9fc6af1a6499e0a4.js +0 -1
  254. fides/ui-build/static/admin/_next/static/chunks/5574-a4047e826a8cd4c3.js +0 -1
  255. fides/ui-build/static/admin/_next/static/chunks/5834-bd9ed01c4ab2ef5c.js +0 -1
  256. fides/ui-build/static/admin/_next/static/chunks/5960-8895f51b30c35798.js +0 -1
  257. fides/ui-build/static/admin/_next/static/chunks/5973-67c7562997f7d5cb.js +0 -1
  258. fides/ui-build/static/admin/_next/static/chunks/6277-515c922445b8edc5.js +0 -1
  259. fides/ui-build/static/admin/_next/static/chunks/6954-6eb480eb132239c3.js +0 -1
  260. fides/ui-build/static/admin/_next/static/chunks/7044-9dc90893067f38ae.js +0 -1
  261. fides/ui-build/static/admin/_next/static/chunks/7980-2597c279c30fbcda.js +0 -1
  262. fides/ui-build/static/admin/_next/static/chunks/7c79804f.26834f883d5ad770.js +0 -1
  263. fides/ui-build/static/admin/_next/static/chunks/8837-cf26e5ca1ae5aaf5.js +0 -1
  264. fides/ui-build/static/admin/_next/static/chunks/9282-1a5a2f6f4d9ed586.js +0 -1
  265. fides/ui-build/static/admin/_next/static/chunks/9676.f4d5977a5f148797.js +0 -1
  266. fides/ui-build/static/admin/_next/static/chunks/9767-4c591bd478c72650.js +0 -1
  267. fides/ui-build/static/admin/_next/static/chunks/main-ce7f38a12ea8c223.js +0 -1
  268. fides/ui-build/static/admin/_next/static/chunks/pages/_app-9ceff88561dc1250.js +0 -909
  269. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-136bcbd20ac59bf5.js +0 -1
  270. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-e11ace4f273ebb47.js +0 -1
  271. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-97fea4ac45093cbd.js +0 -1
  272. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-942d68a88b321067.js +0 -1
  273. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-00526324583139ab.js +0 -1
  274. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-f0ab51d0d5f995de.js +0 -1
  275. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-2220c30c3863b5a5.js +0 -1
  276. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-ab9bc1a3640547db.js +0 -1
  277. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-17ec8385bb1fa6d4.js +0 -1
  278. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-740824dfa6823e26.js +0 -1
  279. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-5541ecd2f62711a5.js +0 -1
  280. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-b8eaa9b9d3832b30.js +0 -1
  281. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-a6448ce6ba7f0cf5.js +0 -1
  282. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-1a6965d78bfb26b0.js +0 -1
  283. fides/ui-build/static/admin/_next/static/chunks/pages/messaging-f263e6bacf0f2d19.js +0 -1
  284. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-b96ee3fea3920fcf.js +0 -1
  285. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-1b0f9469cb65abfc.js +0 -1
  286. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-eebd2f4ead19cfd6.js +0 -1
  287. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-a3fa3ad77730a03b.js +0 -1
  288. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-4769f55b138073f7.js +0 -1
  289. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-775f55b3f80cd452.js +0 -1
  290. fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-14def4ca3cc9cda5.js +0 -1
  291. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-21f26c0dc4d09e9f.js +0 -1
  292. fides/ui-build/static/admin/_next/static/css/957d0e4fea846ff0.css +0 -1
  293. fides/ui-build/static/admin/_next/static/rOPehh5NMs1hjog7nTw1q/_buildManifest.js +0 -1
  294. fides/ui-build/static/admin/_next/static/rOPehh5NMs1hjog7nTw1q/_ssgManifest.js +0 -1
  295. {ethyca_fides-2.57.1rc0.dist-info → ethyca_fides-2.58.0.dist-info}/LICENSE +0 -0
  296. {ethyca_fides-2.57.1rc0.dist-info → ethyca_fides-2.58.0.dist-info}/WHEEL +0 -0
  297. {ethyca_fides-2.57.1rc0.dist-info → ethyca_fides-2.58.0.dist-info}/entry_points.txt +0 -0
  298. {ethyca_fides-2.57.1rc0.dist-info → ethyca_fides-2.58.0.dist-info}/top_level.txt +0 -0
  299. /fides/ui-build/static/admin/_next/static/chunks/pages/user-management/{new-d6717378b42982d5.js → new-be690621a944bfe2.js} +0 -0
@@ -4,27 +4,16 @@ from __future__ import annotations
4
4
 
5
5
  import json
6
6
  from datetime import datetime, timedelta
7
- from enum import Enum as EnumType
8
- from typing import Any, Dict, List, Optional, Set, Tuple, Union
7
+ from typing import TYPE_CHECKING, Any, Dict, List, Optional, Set, Union
9
8
 
10
9
  from celery.result import AsyncResult
11
10
  from loguru import logger
12
- from pydantic import BaseModel, ConfigDict
13
- from sqlalchemy import (
14
- Boolean,
15
- Column,
16
- DateTime,
17
- ForeignKey,
18
- Integer,
19
- String,
20
- UniqueConstraint,
21
- )
11
+ from sqlalchemy import Boolean, Column, DateTime, ForeignKey, Integer, String
22
12
  from sqlalchemy.dialects.postgresql import JSONB
23
13
  from sqlalchemy.ext.declarative import declared_attr
24
14
  from sqlalchemy.ext.mutable import MutableDict, MutableList
25
15
  from sqlalchemy.orm import Query, RelationshipProperty, Session, backref, relationship
26
16
  from sqlalchemy.orm.dynamic import AppenderQuery
27
- from sqlalchemy.sql import text
28
17
  from sqlalchemy_utils.types.encrypted.encrypted_type import (
29
18
  AesGcmEngine,
30
19
  StringEncryptedType,
@@ -50,8 +39,10 @@ from fides.api.graph.config import (
50
39
  CollectionAddress,
51
40
  )
52
41
  from fides.api.migrations.hash_migration_mixin import HashMigrationMixin
42
+ from fides.api.models.attachment import Attachment, AttachmentReference
53
43
  from fides.api.models.audit_log import AuditLog
54
44
  from fides.api.models.client import ClientDetail
45
+ from fides.api.models.comment import Comment, CommentReference
55
46
  from fides.api.models.fides_user import FidesUser
56
47
  from fides.api.models.manual_webhook import AccessManualWebhook
57
48
  from fides.api.models.policy import (
@@ -64,14 +55,21 @@ from fides.api.models.pre_approval_webhook import (
64
55
  PreApprovalWebhook,
65
56
  PreApprovalWebhookReply,
66
57
  )
67
- from fides.api.oauth.jwt import generate_jwe
68
- from fides.api.schemas.base_class import FidesSchema
69
- from fides.api.schemas.drp_privacy_request import DrpPrivacyRequestCreate
70
- from fides.api.schemas.external_https import (
71
- RequestTaskJWE,
72
- SecondPartyResponseFormat,
73
- WebhookJWE,
58
+ from fides.api.models.privacy_request.execution_log import (
59
+ COMPLETED_EXECUTION_LOG_STATUSES,
60
+ EXITED_EXECUTION_LOG_STATUSES,
61
+ ExecutionLog,
62
+ )
63
+ from fides.api.models.privacy_request.provided_identity import ProvidedIdentity
64
+ from fides.api.models.privacy_request.request_task import RequestTask
65
+ from fides.api.models.privacy_request.webhook import (
66
+ CallbackType,
67
+ SecondPartyRequestFormat,
68
+ generate_request_callback_pre_approval_jwe,
69
+ generate_request_callback_resume_jwe,
74
70
  )
71
+ from fides.api.schemas.drp_privacy_request import DrpPrivacyRequestCreate
72
+ from fides.api.schemas.external_https import SecondPartyResponseFormat
75
73
  from fides.api.schemas.masking.masking_secrets import MaskingSecretCache
76
74
  from fides.api.schemas.policy import ActionType, CurrentStep
77
75
  from fides.api.schemas.privacy_request import (
@@ -84,16 +82,10 @@ from fides.api.schemas.privacy_request import (
84
82
  from fides.api.schemas.redis_cache import (
85
83
  CustomPrivacyRequestField as CustomPrivacyRequestFieldSchema,
86
84
  )
87
- from fides.api.schemas.redis_cache import (
88
- Identity,
89
- IdentityBase,
90
- LabeledIdentity,
91
- MultiValue,
92
- )
85
+ from fides.api.schemas.redis_cache import Identity, LabeledIdentity, MultiValue
93
86
  from fides.api.tasks import celery_app
94
87
  from fides.api.util.cache import (
95
88
  FidesopsRedis,
96
- celery_tasks_in_flight,
97
89
  get_all_cache_keys_for_privacy_request,
98
90
  get_async_task_tracking_cache_key,
99
91
  get_cache,
@@ -110,98 +102,12 @@ from fides.api.util.decrypted_identity_automaton import DecryptedIdentityAutomat
110
102
  from fides.api.util.identity_verification import IdentityVerificationMixin
111
103
  from fides.api.util.logger import Pii
112
104
  from fides.api.util.logger_context_utils import Contextualizable, LoggerContextKeys
113
- from fides.common.api.scope_registry import (
114
- PRIVACY_REQUEST_CALLBACK_RESUME,
115
- PRIVACY_REQUEST_REVIEW,
116
- )
117
105
  from fides.config import CONFIG
118
106
 
119
- # Locations from which privacy request execution can be resumed, in order.
120
- EXECUTION_CHECKPOINTS = [
121
- CurrentStep.pre_webhooks,
122
- CurrentStep.access,
123
- CurrentStep.upload_access,
124
- CurrentStep.erasure,
125
- CurrentStep.finalize_erasure,
126
- CurrentStep.consent,
127
- CurrentStep.finalize_consent,
128
- CurrentStep.email_post_send,
129
- CurrentStep.post_webhooks,
130
- ]
131
-
132
-
133
- EmailRequestFulfillmentBodyParams = Dict[
134
- CollectionAddress, Optional[CheckpointActionRequired]
135
- ]
136
-
137
-
138
- class CallbackType(EnumType):
139
- """We currently have three types of Webhooks: pre-approval, pre (-execution), post (-execution)"""
140
-
141
- pre_approval = "pre_approval"
142
- pre = "pre" # pre-execution
143
- post = "post" # post-execution
144
-
145
-
146
- class SecondPartyRequestFormat(BaseModel):
147
- """
148
- The request body we will use when calling a user's HTTP endpoint from fides.api
149
- This class is defined here to avoid circular import issues between this file and
150
- models.policy
151
- """
152
-
153
- privacy_request_id: str
154
- privacy_request_status: PrivacyRequestStatus
155
- direction: WebhookDirection
156
- callback_type: CallbackType
157
- identity: Identity
158
- policy_action: Optional[ActionType] = None
159
- model_config = ConfigDict(use_enum_values=True)
160
-
161
-
162
- def generate_request_callback_resume_jwe(webhook: PolicyPreWebhook) -> str:
163
- """
164
- Generate a JWE to be used to resume privacy request execution.
165
- """
166
- jwe = WebhookJWE(
167
- webhook_id=webhook.id,
168
- scopes=[PRIVACY_REQUEST_CALLBACK_RESUME],
169
- iat=datetime.now().isoformat(),
170
- )
171
- return generate_jwe(
172
- json.dumps(jwe.model_dump(mode="json")),
173
- CONFIG.security.app_encryption_key,
174
- )
175
-
176
-
177
- def generate_request_callback_pre_approval_jwe(webhook: PreApprovalWebhook) -> str:
178
- """
179
- Generate a JWE to be used to mark privacy requests as eligible / not-eligible for pre approval.
180
- """
181
- jwe = WebhookJWE(
182
- webhook_id=webhook.id,
183
- scopes=[PRIVACY_REQUEST_REVIEW],
184
- iat=datetime.now().isoformat(),
185
- )
186
- return generate_jwe(
187
- json.dumps(jwe.model_dump(mode="json")),
188
- CONFIG.security.app_encryption_key,
189
- )
190
-
191
-
192
- def generate_request_task_callback_jwe(request_task: RequestTask) -> str:
193
- """
194
- Generate a JWE to be used to resume privacy request execution when a
195
- callback endpoint is hit for a RequestTask
196
- """
197
- jwe = RequestTaskJWE(
198
- request_task_id=request_task.id,
199
- scopes=[PRIVACY_REQUEST_CALLBACK_RESUME],
200
- iat=datetime.now().isoformat(),
201
- )
202
- return generate_jwe(
203
- json.dumps(jwe.model_dump(mode="json")),
204
- CONFIG.security.app_encryption_key,
107
+ if TYPE_CHECKING:
108
+ from fides.api.models.privacy_request.consent import ( # type: ignore[attr-defined]
109
+ Consent,
110
+ ConsentRequest,
205
111
  )
206
112
 
207
113
 
@@ -262,6 +168,20 @@ class PrivacyRequest(
262
168
  Policy,
263
169
  backref="privacy_requests",
264
170
  )
171
+ attachments = relationship(
172
+ Attachment,
173
+ secondary="attachment_reference",
174
+ primaryjoin="PrivacyRequest.id == AttachmentReference.reference_id",
175
+ secondaryjoin="Attachment.id == AttachmentReference.attachment_id",
176
+ order_by="Attachment.created_at",
177
+ )
178
+ comments = relationship(
179
+ Comment,
180
+ secondary="comment_reference",
181
+ primaryjoin="PrivacyRequest.id == CommentReference.reference_id",
182
+ secondaryjoin="Comment.id == CommentReference.comment_id",
183
+ order_by="Comment.created_at",
184
+ )
265
185
  property_id = Column(String, nullable=True)
266
186
 
267
187
  cancel_reason = Column(String(200))
@@ -1107,6 +1027,51 @@ class PrivacyRequest(
1107
1027
  """Return existing Consent Request Tasks for the current privacy request"""
1108
1028
  return self.request_tasks.filter(RequestTask.action_type == ActionType.consent)
1109
1029
 
1030
+ def get_comment_by_id(self, db: Session, comment_id: str) -> Optional[Comment]:
1031
+ """Get the comment associated with the privacy request"""
1032
+ comment = (
1033
+ db.query(Comment)
1034
+ .join(CommentReference, Comment.id == CommentReference.comment_id)
1035
+ .filter(
1036
+ CommentReference.reference_id
1037
+ == self.id, # Ensure the comment is linked to this privacy request
1038
+ Comment.id == comment_id, # Match the specific comment ID
1039
+ )
1040
+ .first()
1041
+ )
1042
+ if not comment:
1043
+ logger.info(
1044
+ f"Comment with id {comment_id} not found on privacy request {self.id}"
1045
+ )
1046
+ return comment
1047
+
1048
+ def get_attachment_by_id(
1049
+ self, db: Session, attachment_id: str
1050
+ ) -> Optional[Attachment]:
1051
+ """Get the attachment associated with the privacy request"""
1052
+ attachment = (
1053
+ db.query(Attachment)
1054
+ .join(
1055
+ AttachmentReference, Attachment.id == AttachmentReference.attachment_id
1056
+ )
1057
+ .filter(
1058
+ AttachmentReference.reference_id == self.id,
1059
+ Attachment.id == attachment_id,
1060
+ )
1061
+ .first()
1062
+ )
1063
+ if not attachment:
1064
+ logger.info(
1065
+ f"Attachment with id {attachment_id} not found on privacy request {self.id}"
1066
+ )
1067
+ return attachment
1068
+
1069
+ def delete_attachment_by_id(self, db: Session, attachment_id: str) -> None:
1070
+ """Delete the attachment associated with the privacy request"""
1071
+ attachment = self.get_attachment_by_id(db, attachment_id)
1072
+ if attachment:
1073
+ attachment.delete(db)
1074
+
1110
1075
  def get_existing_request_task(
1111
1076
  self,
1112
1077
  db: Session,
@@ -1377,128 +1342,6 @@ class PrivacyRequestNotifications(Base):
1377
1342
  notify_after_failures = Column(Integer, nullable=False)
1378
1343
 
1379
1344
 
1380
- class ProvidedIdentityType(EnumType):
1381
- """Enum for privacy request identity types"""
1382
-
1383
- email = "email"
1384
- phone_number = "phone_number"
1385
- ga_client_id = "ga_client_id"
1386
- ljt_readerID = "ljt_readerID"
1387
- fides_user_device_id = "fides_user_device_id"
1388
- external_id = "external_id"
1389
-
1390
-
1391
- class ProvidedIdentity(HashMigrationMixin, Base): # pylint: disable=R0904
1392
- """
1393
- A table for storing identity fields and values provided at privacy request
1394
- creation time.
1395
- """
1396
-
1397
- privacy_request_id = Column(
1398
- String,
1399
- ForeignKey(
1400
- PrivacyRequest.id_field_path, ondelete="CASCADE", onupdate="CASCADE"
1401
- ),
1402
- )
1403
- privacy_request = relationship(
1404
- PrivacyRequest,
1405
- backref="provided_identities",
1406
- ) # Which privacy request this identity belongs to
1407
-
1408
- field_name = Column(
1409
- String,
1410
- index=False,
1411
- nullable=False,
1412
- )
1413
- field_label = Column(
1414
- String,
1415
- index=False,
1416
- nullable=True,
1417
- )
1418
- hashed_value = Column(
1419
- String,
1420
- index=True,
1421
- unique=False,
1422
- nullable=True,
1423
- ) # This field is used as a blind index for exact match searches
1424
- encrypted_value = Column(
1425
- MutableDict.as_mutable(
1426
- StringEncryptedType(
1427
- JSONTypeOverride,
1428
- CONFIG.security.app_encryption_key,
1429
- AesGcmEngine,
1430
- "pkcs5",
1431
- )
1432
- ),
1433
- nullable=True,
1434
- ) # Type bytea in the db
1435
- consent = relationship(
1436
- "Consent", back_populates="provided_identity", cascade="delete, delete-orphan"
1437
- )
1438
- consent_request = relationship(
1439
- "ConsentRequest",
1440
- back_populates="provided_identity",
1441
- cascade="delete, delete-orphan",
1442
- )
1443
-
1444
- @classmethod
1445
- def bcrypt_hash_value(
1446
- cls,
1447
- value: MultiValue,
1448
- encoding: str = "UTF-8",
1449
- ) -> str:
1450
- """
1451
- Temporary function used to hash values to the previously used bcrypt hashes.
1452
- This can be removed once the bcrypt to SHA-256 migration is complete.
1453
- """
1454
-
1455
- SALT = "$2b$12$UErimNtlsE6qgYf2BrI1Du"
1456
- value_str = str(value)
1457
- hashed_value = hash_credential_with_salt(
1458
- value_str.encode(encoding),
1459
- SALT.encode(encoding),
1460
- )
1461
- return hashed_value
1462
-
1463
- @classmethod
1464
- def hash_value(
1465
- cls,
1466
- value: MultiValue,
1467
- encoding: str = "UTF-8",
1468
- ) -> str:
1469
- """Utility function to hash the value with a generated salt"""
1470
- SALT = get_identity_salt()
1471
- value_str = str(value)
1472
- hashed_value = hash_value_with_salt(
1473
- value_str.encode(encoding),
1474
- SALT.encode(encoding),
1475
- )
1476
- return hashed_value
1477
-
1478
- def migrate_hashed_fields(self) -> None:
1479
- if value := self.encrypted_value.get("value"):
1480
- self.hashed_value = self.hash_value(value)
1481
- self.is_hash_migrated = True
1482
-
1483
- def as_identity_schema(self) -> Identity:
1484
- """Creates an Identity schema from a ProvidedIdentity record in the application DB."""
1485
-
1486
- identity_dict = {}
1487
- if any(
1488
- [
1489
- not self.field_name,
1490
- not self.encrypted_value,
1491
- ]
1492
- ):
1493
- return Identity()
1494
-
1495
- value = self.encrypted_value.get("value") # type:ignore
1496
- if self.field_label:
1497
- value = LabeledIdentity(label=self.field_label, value=value)
1498
- identity_dict[self.field_name] = value
1499
- return Identity(**identity_dict)
1500
-
1501
-
1502
1345
  class CustomPrivacyRequestField(HashMigrationMixin, Base):
1503
1346
  @declared_attr
1504
1347
  def __tablename__(self) -> str:
@@ -1601,135 +1444,6 @@ class CustomPrivacyRequestField(HashMigrationMixin, Base):
1601
1444
  self.is_hash_migrated = True
1602
1445
 
1603
1446
 
1604
- class Consent(Base):
1605
- """The DB ORM model for Consent."""
1606
-
1607
- provided_identity_id = Column(
1608
- String,
1609
- ForeignKey(ProvidedIdentity.id),
1610
- nullable=False,
1611
- )
1612
- data_use = Column(String, nullable=False)
1613
- data_use_description = Column(String)
1614
- opt_in = Column(Boolean, nullable=False)
1615
- has_gpc_flag = Column(
1616
- Boolean,
1617
- server_default="f",
1618
- default=False,
1619
- nullable=False,
1620
- )
1621
- conflicts_with_gpc = Column(
1622
- Boolean,
1623
- server_default="f",
1624
- default=False,
1625
- nullable=False,
1626
- )
1627
-
1628
- provided_identity = relationship(ProvidedIdentity, back_populates="consent")
1629
-
1630
- UniqueConstraint(provided_identity_id, data_use, name="uix_identity_data_use")
1631
-
1632
- identity: Optional[IdentityBase] = None
1633
-
1634
-
1635
- class ConsentRequest(IdentityVerificationMixin, Base):
1636
- """Tracks consent requests."""
1637
-
1638
- property_id = Column(
1639
- String,
1640
- nullable=True,
1641
- )
1642
- provided_identity_id = Column(
1643
- String, ForeignKey(ProvidedIdentity.id), nullable=False
1644
- )
1645
- provided_identity = relationship(
1646
- ProvidedIdentity,
1647
- back_populates="consent_request",
1648
- )
1649
-
1650
- custom_fields = relationship(
1651
- CustomPrivacyRequestField, back_populates="consent_request"
1652
- )
1653
-
1654
- preferences = Column(
1655
- MutableList.as_mutable(JSONB),
1656
- nullable=True,
1657
- )
1658
-
1659
- identity_verified_at = Column(
1660
- DateTime(timezone=True),
1661
- nullable=True,
1662
- )
1663
-
1664
- source = Column(EnumColumn(PrivacyRequestSource), nullable=True)
1665
-
1666
- privacy_request_id = Column(String, ForeignKey(PrivacyRequest.id), nullable=True)
1667
- privacy_request = relationship(PrivacyRequest)
1668
-
1669
- def get_cached_identity_data(self) -> Dict[str, Any]:
1670
- """Retrieves any identity data pertaining to this request from the cache."""
1671
- prefix = f"id-{self.id}-identity-*"
1672
- cache: FidesopsRedis = get_cache()
1673
- keys = cache.keys(prefix)
1674
- return {key.split("-")[-1]: cache.get(key) for key in keys}
1675
-
1676
- def verify_identity(
1677
- self,
1678
- db: Session,
1679
- provided_code: Optional[str] = None,
1680
- ) -> None:
1681
- """
1682
- A method to call the internal identity verification method provided by the
1683
- `IdentityVerificationMixin`.
1684
- """
1685
- self._verify_identity(provided_code=provided_code)
1686
- self.identity_verified_at = datetime.utcnow()
1687
- self.save(db)
1688
-
1689
- def persist_custom_privacy_request_fields(
1690
- self,
1691
- db: Session,
1692
- custom_privacy_request_fields: Optional[
1693
- Dict[str, CustomPrivacyRequestFieldSchema]
1694
- ],
1695
- ) -> None:
1696
- if not custom_privacy_request_fields:
1697
- return
1698
-
1699
- if CONFIG.execution.allow_custom_privacy_request_field_collection:
1700
- for key, item in custom_privacy_request_fields.items():
1701
- if item.value:
1702
- hashed_value = CustomPrivacyRequestField.hash_value(item.value)
1703
- CustomPrivacyRequestField.create(
1704
- db=db,
1705
- data={
1706
- "consent_request_id": self.id,
1707
- "field_name": key,
1708
- "field_label": item.label,
1709
- "encrypted_value": {"value": item.value},
1710
- "hashed_value": hashed_value,
1711
- },
1712
- )
1713
- else:
1714
- logger.info(
1715
- "Custom fields provided in consent request {}, but config setting 'CONFIG.execution.allow_custom_privacy_request_field_collection' prevents their storage.",
1716
- self.id,
1717
- )
1718
-
1719
- def get_persisted_custom_privacy_request_fields(self) -> Dict[str, Any]:
1720
- return {
1721
- field.field_name: {
1722
- "label": field.field_label,
1723
- "value": field.encrypted_value["value"],
1724
- }
1725
- for field in self.custom_fields # type: ignore[attr-defined]
1726
- }
1727
-
1728
-
1729
- # Unique text to separate a step from a collection address, so we can store two values in one.
1730
- PAUSED_SEPARATOR = "__fidesops_paused_sep__"
1731
-
1732
-
1733
1447
  def cache_action_required(
1734
1448
  cache_key: str,
1735
1449
  step: Optional[CurrentStep] = None,
@@ -1773,86 +1487,6 @@ def get_action_required_details(
1773
1487
  return None
1774
1488
 
1775
1489
 
1776
- COMPLETED_EXECUTION_LOG_STATUSES = [
1777
- ExecutionLogStatus.complete,
1778
- ExecutionLogStatus.skipped,
1779
- ]
1780
- EXITED_EXECUTION_LOG_STATUSES = [
1781
- ExecutionLogStatus.complete,
1782
- ExecutionLogStatus.error,
1783
- ExecutionLogStatus.skipped,
1784
- ]
1785
-
1786
-
1787
- class ExecutionLog(Base):
1788
- """
1789
- Stores the individual execution logs associated with a PrivacyRequest.
1790
-
1791
- Execution logs contain information about the individual queries as they progress through the workflow
1792
- generated by the query builder.
1793
- """
1794
-
1795
- connection_key = Column(String, index=True)
1796
- # Name of the fides-annotated dataset, for example: my-mongo-db
1797
- dataset_name = Column(String, index=True)
1798
- # Name of the particular collection or table affected
1799
- collection_name = Column(String, index=True)
1800
- # A JSON Array describing affected fields along with their data categories and paths
1801
- fields_affected = Column(MutableList.as_mutable(JSONB), nullable=True)
1802
- # Contains info, warning, or error messages
1803
- message = Column(String)
1804
- action_type = Column(
1805
- EnumColumn(ActionType),
1806
- index=True,
1807
- nullable=False,
1808
- )
1809
- status = Column(
1810
- EnumColumn(
1811
- ExecutionLogStatus,
1812
- native_enum=True,
1813
- values_callable=lambda x: [
1814
- i.value for i in x
1815
- ], # Using ExecutionLogStatus values in database, even though app is using the names.
1816
- ),
1817
- index=True,
1818
- nullable=False,
1819
- )
1820
-
1821
- privacy_request_id = Column(
1822
- String,
1823
- nullable=False,
1824
- index=True,
1825
- )
1826
-
1827
- # Use clock_timestamp() instead of NOW() to get the actual current time at row creation,
1828
- # regardless of transaction state. This prevents timestamp caching within transactions
1829
- # and ensures more accurate creation times.
1830
- # https://www.postgresql.org/docs/current/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT
1831
-
1832
- created_at = Column(
1833
- DateTime(timezone=True), server_default=text("clock_timestamp()")
1834
- )
1835
- updated_at = Column(
1836
- DateTime(timezone=True),
1837
- server_default=text("clock_timestamp()"),
1838
- onupdate=text("clock_timestamp()"),
1839
- )
1840
-
1841
-
1842
- def can_run_checkpoint(
1843
- request_checkpoint: CurrentStep, from_checkpoint: Optional[CurrentStep] = None
1844
- ) -> bool:
1845
- """Determine whether we should run a specific checkpoint in privacy request execution
1846
-
1847
- If there's no from_checkpoint specified we should always run the current checkpoint.
1848
- """
1849
- if not from_checkpoint:
1850
- return True
1851
- return EXECUTION_CHECKPOINTS.index(
1852
- request_checkpoint
1853
- ) >= EXECUTION_CHECKPOINTS.index(from_checkpoint)
1854
-
1855
-
1856
1490
  def _parse_cache_to_checkpoint_action_required(
1857
1491
  cache: dict[str, Any]
1858
1492
  ) -> CheckpointActionRequired:
@@ -1874,246 +1508,3 @@ def _parse_cache_to_checkpoint_action_required(
1874
1508
  collection=collection,
1875
1509
  action_needed=action_needed,
1876
1510
  )
1877
-
1878
-
1879
- class TraversalDetails(FidesSchema):
1880
- """Schema to format saving pre-calculated traversal details on RequestTask.traversal_details"""
1881
-
1882
- dataset_connection_key: str
1883
- incoming_edges: List[Tuple[str, str]]
1884
- outgoing_edges: List[Tuple[str, str]]
1885
- input_keys: List[str]
1886
- skipped_nodes: Optional[List[Tuple[str, str]]] = None
1887
-
1888
- # TODO: remove this method once we support custom request fields in DSR graph.
1889
- @classmethod
1890
- def create_empty_traversal(cls, connection_key: str) -> TraversalDetails:
1891
- """
1892
- Creates an "empty" TraversalDetails object that only has the dataset connection key set.
1893
- This is a bit of a hacky workaround needed to implement the Dynamic Erasure Emails feature,
1894
- but we should no longer need it once the custom_request_fields are included in our graph
1895
- traversal
1896
- """
1897
- return cls(
1898
- dataset_connection_key=connection_key,
1899
- incoming_edges=[],
1900
- outgoing_edges=[],
1901
- input_keys=[],
1902
- skipped_nodes=[],
1903
- )
1904
-
1905
-
1906
- class RequestTask(Base):
1907
- """
1908
- An individual Task for a Privacy Request.
1909
-
1910
- When we execute a PrivacyRequest, we build a graph by combining the current datasets with the identity data
1911
- and we save the nodes (collections) in the graph as Request Tasks.
1912
-
1913
- Currently, we build access, erasure, and consent Request Tasks.
1914
- """
1915
-
1916
- privacy_request_id = Column(
1917
- String,
1918
- ForeignKey(PrivacyRequest.id_field_path, ondelete="SET NULL"),
1919
- nullable=True,
1920
- index=True,
1921
- )
1922
-
1923
- # Identifiers of this request task
1924
- collection_address = Column(
1925
- String, nullable=False, index=True
1926
- ) # Of the format dataset_name:collection_name for convenience
1927
- dataset_name = Column(String, nullable=False, index=True)
1928
- collection_name = Column(String, nullable=False, index=True)
1929
- action_type = Column(EnumColumn(ActionType), nullable=False, index=True)
1930
-
1931
- # Note that RequestTasks share statuses with ExecutionLogs. When a RequestTask changes state, an ExecutionLog
1932
- # is also created with that state. These are tied tightly together in GraphTask.
1933
- status = Column(
1934
- EnumColumn(
1935
- ExecutionLogStatus,
1936
- native_enum=False,
1937
- values_callable=lambda x: [
1938
- i.value for i in x
1939
- ], # Using ExecutionLogStatus values in database, even though app is using the names.
1940
- ), # character varying in database
1941
- index=True,
1942
- nullable=False,
1943
- )
1944
-
1945
- upstream_tasks = Column(
1946
- MutableList.as_mutable(JSONB)
1947
- ) # List of collection address strings
1948
- downstream_tasks = Column(
1949
- MutableList.as_mutable(JSONB)
1950
- ) # List of collection address strings
1951
- all_descendant_tasks = Column(
1952
- MutableList.as_mutable(JSONB)
1953
- ) # All tasks that can be reached by the current task. This is useful when this task fails,
1954
- # and we can mark every single one of these as failed.
1955
-
1956
- # Raw data retrieved from an access request is stored here. This contains all of the
1957
- # intermediate data we retrieved, needed for downstream tasks, but hasn't been filtered
1958
- # by data category for the end user.
1959
- access_data = Column( # An encrypted JSON String - saved as a list of Rows
1960
- StringEncryptedType(
1961
- type_in=JSONTypeOverride,
1962
- key=CONFIG.security.app_encryption_key,
1963
- engine=AesGcmEngine,
1964
- padding="pkcs5",
1965
- ),
1966
- )
1967
-
1968
- # This is the raw access data saved in erasure format (with placeholders preserved) to perform a masking request.
1969
- # First saved on the access node, and then copied to the corresponding erasure node.
1970
- data_for_erasures = Column( # An encrypted JSON String - saved as a list of rows
1971
- StringEncryptedType(
1972
- type_in=JSONTypeOverride,
1973
- key=CONFIG.security.app_encryption_key,
1974
- engine=AesGcmEngine,
1975
- padding="pkcs5",
1976
- ),
1977
- )
1978
-
1979
- # Written after an erasure is completed
1980
- rows_masked = Column(Integer)
1981
- # Written after a consent request is completed - not all consent
1982
- # connectors will end up sending a request
1983
- consent_sent = Column(Boolean)
1984
-
1985
- # For async tasks awaiting callback
1986
- callback_succeeded = Column(Boolean)
1987
-
1988
- # Stores a serialized collection that can be transformed back into a Collection to help
1989
- # execute the current task
1990
- collection = Column(MutableDict.as_mutable(JSONB))
1991
- # Stores key details from traversal.traverse in the format of TraversalDetails
1992
- traversal_details = Column(MutableDict.as_mutable(JSONB))
1993
-
1994
- privacy_request: RelationshipProperty[PrivacyRequest] = relationship(
1995
- "PrivacyRequest",
1996
- back_populates="request_tasks",
1997
- uselist=False,
1998
- )
1999
-
2000
- @property
2001
- def request_task_address(self) -> CollectionAddress:
2002
- """Convert the collection_address into Collection Address format"""
2003
- return CollectionAddress.from_string(self.collection_address)
2004
-
2005
- @property
2006
- def is_root_task(self) -> bool:
2007
- """Convenience helper for asserting whether the task is a root task"""
2008
- return self.request_task_address == ROOT_COLLECTION_ADDRESS
2009
-
2010
- @property
2011
- def is_terminator_task(self) -> bool:
2012
- """Convenience helper for asserting whether the task is a terminator task"""
2013
- return self.request_task_address == TERMINATOR_ADDRESS
2014
-
2015
- def get_cached_task_id(self) -> Optional[str]:
2016
- """Gets the cached celery task ID for this request task."""
2017
- cache: FidesopsRedis = get_cache()
2018
- task_id = cache.get(get_async_task_tracking_cache_key(self.id))
2019
- return task_id
2020
-
2021
- def get_access_data(self) -> List[Row]:
2022
- """Helper to retrieve access data or default to empty list"""
2023
- return self.access_data or []
2024
-
2025
- def get_data_for_erasures(self) -> List[Row]:
2026
- """Helper to retrieve erasure data needed to build masking requests or default to empty list"""
2027
- return self.data_for_erasures or []
2028
-
2029
- def update_status(self, db: Session, status: ExecutionLogStatus) -> None:
2030
- """Helper method to update a task's status"""
2031
- self.status = status
2032
- self.save(db)
2033
-
2034
- def get_tasks_with_same_action_type(
2035
- self, db: Session, collection_address_str: str
2036
- ) -> Query:
2037
- """Fetch task on the same privacy request and action type as current by collection address"""
2038
- return db.query(RequestTask).filter(
2039
- RequestTask.privacy_request_id == self.privacy_request_id,
2040
- RequestTask.action_type == self.action_type,
2041
- RequestTask.collection_address == collection_address_str,
2042
- )
2043
-
2044
- def get_pending_downstream_tasks(self, db: Session) -> Query:
2045
- """Returns the immediate downstream task objects that are still pending"""
2046
- return db.query(RequestTask).filter(
2047
- RequestTask.privacy_request_id == self.privacy_request_id,
2048
- RequestTask.action_type == self.action_type,
2049
- RequestTask.collection_address.in_(self.downstream_tasks or []),
2050
- RequestTask.status == ExecutionLogStatus.pending,
2051
- )
2052
-
2053
- def can_queue_request_task(self, db: Session, should_log: bool = False) -> bool:
2054
- """Returns True if upstream tasks are complete and the current Request Task
2055
- is not running in another celery task.
2056
-
2057
- This check ignores its database status - that is checked elsewhere.
2058
- """
2059
- return self.upstream_tasks_complete(
2060
- db, should_log
2061
- ) and not self.request_task_running(should_log)
2062
-
2063
- def upstream_tasks_complete(self, db: Session, should_log: bool = False) -> bool:
2064
- """Determines if all of the upstream tasks of the current task are complete"""
2065
- upstream_tasks: Query = self.upstream_tasks_objects(db)
2066
- tasks_complete: bool = all(
2067
- upstream_task.status in COMPLETED_EXECUTION_LOG_STATUSES
2068
- for upstream_task in upstream_tasks
2069
- ) and upstream_tasks.count() == len(self.upstream_tasks or [])
2070
-
2071
- if not tasks_complete and should_log:
2072
- logger.debug(
2073
- "Upstream tasks incomplete for {} task {}.",
2074
- self.action_type.value,
2075
- self.collection_address,
2076
- )
2077
-
2078
- return tasks_complete
2079
-
2080
- def upstream_tasks_objects(self, db: Session) -> Query:
2081
- """Returns Request Task objects that are upstream of the current Request Task"""
2082
- upstream_tasks: Query = db.query(RequestTask).filter(
2083
- RequestTask.privacy_request_id == self.privacy_request_id,
2084
- RequestTask.collection_address.in_(self.upstream_tasks or []),
2085
- RequestTask.action_type == self.action_type,
2086
- )
2087
- return upstream_tasks
2088
-
2089
- def request_task_running(self, should_log: bool = False) -> bool:
2090
- """Returns a rough measure if the Request Task is already running -
2091
- not 100% accurate.
2092
-
2093
- This is further only applicable if you are running workers and
2094
- CONFIG.execution.task_always_eager=False. This is just an extra check to reduce possible
2095
- over-scheduling, but it is also okay if the same node runs multiple times.
2096
- """
2097
- celery_task_id: Optional[str] = self.get_cached_task_id()
2098
- if not celery_task_id:
2099
- return False
2100
-
2101
- if should_log:
2102
- logger.debug(
2103
- "Celery Task ID {} found for {} task {}.",
2104
- celery_task_id,
2105
- self.action_type.value,
2106
- self.collection_address,
2107
- )
2108
-
2109
- task_in_flight: bool = celery_tasks_in_flight([celery_task_id])
2110
-
2111
- if task_in_flight and should_log:
2112
- logger.debug(
2113
- "Celery Task {} already processing for {} task {}.",
2114
- celery_task_id,
2115
- self.action_type.value,
2116
- self.collection_address,
2117
- )
2118
-
2119
- return task_in_flight