ethyca-fides 2.57.1b6__py2.py3-none-any.whl → 2.57.1b8__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 (229) hide show
  1. {ethyca_fides-2.57.1b6.dist-info → ethyca_fides-2.57.1b8.dist-info}/METADATA +1 -1
  2. {ethyca_fides-2.57.1b6.dist-info → ethyca_fides-2.57.1b8.dist-info}/RECORD +199 -198
  3. fides/_version.py +3 -3
  4. fides/api/api/v1/endpoints/config_endpoints.py +4 -2
  5. fides/api/api/v1/endpoints/generic_overrides.py +43 -6
  6. fides/api/main.py +4 -1
  7. fides/api/models/attachment.py +6 -8
  8. fides/api/models/comment.py +17 -17
  9. fides/api/models/connectionconfig.py +1 -1
  10. fides/api/models/privacy_request/privacy_request.py +61 -0
  11. fides/api/oauth/utils.py +11 -11
  12. fides/api/schemas/dataset.py +22 -2
  13. fides/api/service/privacy_request/request_runner_service.py +8 -4
  14. fides/api/service/storage/s3.py +133 -0
  15. fides/api/service/storage/util.py +10 -0
  16. fides/api/tasks/__init__.py +3 -1
  17. fides/api/tasks/storage.py +12 -111
  18. fides/config/__init__.py +1 -1
  19. fides/ui-build/static/admin/404.html +1 -1
  20. fides/ui-build/static/admin/_next/static/chunks/1376-c177d8d0c60b1166.js +1 -0
  21. fides/ui-build/static/admin/_next/static/chunks/3320-317483e6c10bae51.js +1 -0
  22. fides/ui-build/static/admin/_next/static/chunks/355-6a87b50acf54e985.js +1 -0
  23. fides/ui-build/static/admin/_next/static/chunks/3662-6a0cafa3023aa7a2.js +1 -0
  24. fides/ui-build/static/admin/_next/static/chunks/4723-1a785d558dfb6441.js +1 -0
  25. fides/ui-build/static/admin/_next/static/chunks/605-c782df008a0ff167.js +1 -0
  26. fides/ui-build/static/admin/_next/static/chunks/6362-72451aeb32815d26.js +1 -0
  27. fides/ui-build/static/admin/_next/static/chunks/6954-f7daf613febc36ef.js +1 -0
  28. fides/ui-build/static/admin/_next/static/chunks/7434-3d4a0beb84ec57f7.js +1 -0
  29. fides/ui-build/static/admin/_next/static/chunks/7495-2f5c8dfba2eabb4f.js +1 -0
  30. fides/ui-build/static/admin/_next/static/chunks/7958-d2bc63e1be612f36.js +1 -0
  31. fides/ui-build/static/admin/_next/static/chunks/7980-91800d54c5964ba3.js +1 -0
  32. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-de85703aa2346f42.js → _app-e53d13729068a001.js} +8 -8
  33. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-05ab19822a7e9f80.js → manual-5593bb1b6de0473d.js} +1 -1
  34. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-18b0b521255289a3.js → multiple-6a7208eee5e588fb.js} +1 -1
  35. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-a33f82e79cb09478.js +1 -0
  36. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-64f83e9a2b777bf3.js → add-vendors-ba0c5fa9764cbd89.js} +1 -1
  37. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-e11ace4f273ebb47.js → configure-1af99ffa7a507e86.js} +1 -1
  38. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-443e6dd191ce5588.js → [id]-c02510104f9e503a.js} +1 -1
  39. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{new-36162d5bea29dcc2.js → new-e96415629f3b4223.js} +1 -1
  40. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-2d651499c07d12d9.js → [id]-66827da90b8a2d1e.js} +1 -1
  41. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-36e57d2f2446be82.js → new-13d48f980bf707e5.js} +1 -1
  42. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-1a3bb713fc7bc298.js +1 -0
  43. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-5892ca5d93ea6165.js +1 -0
  44. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-4fac7e0a54eebc32.js +1 -0
  45. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-45016545c099e183.js +1 -0
  46. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-5ddd3cd7d29e89c0.js +1 -0
  47. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-0616437e1a82d3ed.js → [id]-9bb953098f68f1ee.js} +1 -1
  48. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-f8218440494e8532.js → new-cdcf42d4cb24b45a.js} +1 -1
  49. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-108945832a7edd7d.js +1 -0
  50. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-e96e959d10afebea.js +1 -0
  51. fides/ui-build/static/admin/_next/static/chunks/pages/messaging-5a161e167c251519.js +1 -0
  52. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-c3e234ad95e6e213.js +1 -0
  53. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-347e203faa31716f.js +1 -0
  54. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-729fa8ed0f10bc8e.js +1 -0
  55. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-ff6edba56dfec090.js +1 -0
  56. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-ad368857e86fe01b.js +1 -0
  57. fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-f45920358a405167.js +1 -0
  58. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-ca753b60ca1745c5.js → [id]-44f7fbfee9cf9267.js} +1 -1
  59. fides/ui-build/static/admin/_next/static/css/dd9922a434d21e22.css +1 -0
  60. fides/ui-build/static/admin/_next/static/lO31cDp9wEzsNdiUnl8It/_buildManifest.js +1 -0
  61. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  62. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  63. fides/ui-build/static/admin/add-systems.html +1 -1
  64. fides/ui-build/static/admin/ant-poc.html +1 -1
  65. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  66. fides/ui-build/static/admin/consent/configure.html +1 -1
  67. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  68. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  69. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  70. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  71. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  72. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  73. fides/ui-build/static/admin/consent/properties.html +1 -1
  74. fides/ui-build/static/admin/consent/reporting.html +1 -1
  75. fides/ui-build/static/admin/consent.html +1 -1
  76. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  77. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  78. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  79. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  80. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  81. fides/ui-build/static/admin/data-catalog.html +1 -1
  82. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  83. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  84. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  85. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  86. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  87. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  88. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  89. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  90. fides/ui-build/static/admin/datamap.html +1 -1
  91. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  92. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  93. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  94. fides/ui-build/static/admin/dataset/new.html +1 -1
  95. fides/ui-build/static/admin/dataset.html +1 -1
  96. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  97. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  98. fides/ui-build/static/admin/datastore-connection.html +1 -1
  99. fides/ui-build/static/admin/index.html +1 -1
  100. fides/ui-build/static/admin/integrations/[id].html +1 -1
  101. fides/ui-build/static/admin/integrations.html +1 -1
  102. fides/ui-build/static/admin/lib/fides-ext-gpp.js +1 -1
  103. fides/ui-build/static/admin/lib/fides-tcf.js +1 -1
  104. fides/ui-build/static/admin/login/[provider].html +1 -1
  105. fides/ui-build/static/admin/login.html +1 -1
  106. fides/ui-build/static/admin/messaging/[id].html +1 -1
  107. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  108. fides/ui-build/static/admin/messaging.html +1 -1
  109. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  110. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  111. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  112. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  113. fides/ui-build/static/admin/privacy-requests.html +1 -1
  114. fides/ui-build/static/admin/properties/[id].html +1 -1
  115. fides/ui-build/static/admin/properties/add-property.html +1 -1
  116. fides/ui-build/static/admin/properties.html +1 -1
  117. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  118. fides/ui-build/static/admin/settings/about.html +1 -1
  119. fides/ui-build/static/admin/settings/consent.html +1 -1
  120. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  121. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  122. fides/ui-build/static/admin/settings/domains.html +1 -1
  123. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  124. fides/ui-build/static/admin/settings/locations.html +1 -1
  125. fides/ui-build/static/admin/settings/organization.html +1 -1
  126. fides/ui-build/static/admin/settings/regulations.html +1 -1
  127. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  128. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  129. fides/ui-build/static/admin/systems.html +1 -1
  130. fides/ui-build/static/admin/taxonomy.html +1 -1
  131. fides/ui-build/static/admin/user-management/new.html +1 -1
  132. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  133. fides/ui-build/static/admin/user-management.html +1 -1
  134. fides/ui-build/static/admin/_next/static/NgZHwKJoepGB5-XW8xdZo/_buildManifest.js +0 -1
  135. fides/ui-build/static/admin/_next/static/chunks/3215-c8c683b93919e0a5.js +0 -1
  136. fides/ui-build/static/admin/_next/static/chunks/3320-87c75df57a47487e.js +0 -1
  137. fides/ui-build/static/admin/_next/static/chunks/3662-420d9807c30008ab.js +0 -1
  138. fides/ui-build/static/admin/_next/static/chunks/3949-9888699e2ac564c4.js +0 -1
  139. fides/ui-build/static/admin/_next/static/chunks/4723-81d28e5be5c7b6d7.js +0 -1
  140. fides/ui-build/static/admin/_next/static/chunks/5574-a4047e826a8cd4c3.js +0 -1
  141. fides/ui-build/static/admin/_next/static/chunks/5834-bd9ed01c4ab2ef5c.js +0 -1
  142. fides/ui-build/static/admin/_next/static/chunks/5973-3226fe183b48668b.js +0 -1
  143. fides/ui-build/static/admin/_next/static/chunks/6277-cad7c7c8cf48dbec.js +0 -1
  144. fides/ui-build/static/admin/_next/static/chunks/6954-6eb480eb132239c3.js +0 -1
  145. fides/ui-build/static/admin/_next/static/chunks/7044-88111db2aca2cf65.js +0 -1
  146. fides/ui-build/static/admin/_next/static/chunks/7980-2597c279c30fbcda.js +0 -1
  147. fides/ui-build/static/admin/_next/static/chunks/9767-9af77524ed1648c1.js +0 -1
  148. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-136bcbd20ac59bf5.js +0 -1
  149. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-942d68a88b321067.js +0 -1
  150. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-214f8f89b94c3842.js +0 -1
  151. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-08e6d8bd6e91ee73.js +0 -1
  152. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-740824dfa6823e26.js +0 -1
  153. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-5541ecd2f62711a5.js +0 -1
  154. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-a8e08ecb0c6c3a7c.js +0 -1
  155. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-1a6965d78bfb26b0.js +0 -1
  156. fides/ui-build/static/admin/_next/static/chunks/pages/messaging-f263e6bacf0f2d19.js +0 -1
  157. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-b96ee3fea3920fcf.js +0 -1
  158. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-1b0f9469cb65abfc.js +0 -1
  159. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-eebd2f4ead19cfd6.js +0 -1
  160. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-4769f55b138073f7.js +0 -1
  161. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-775f55b3f80cd452.js +0 -1
  162. fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-14def4ca3cc9cda5.js +0 -1
  163. fides/ui-build/static/admin/_next/static/css/957d0e4fea846ff0.css +0 -1
  164. {ethyca_fides-2.57.1b6.dist-info → ethyca_fides-2.57.1b8.dist-info}/LICENSE +0 -0
  165. {ethyca_fides-2.57.1b6.dist-info → ethyca_fides-2.57.1b8.dist-info}/WHEEL +0 -0
  166. {ethyca_fides-2.57.1b6.dist-info → ethyca_fides-2.57.1b8.dist-info}/entry_points.txt +0 -0
  167. {ethyca_fides-2.57.1b6.dist-info → ethyca_fides-2.57.1b8.dist-info}/top_level.txt +0 -0
  168. /fides/ui-build/static/admin/_next/static/chunks/{1150-73440d7b319558e8.js → 1150-d4a5eef84e70de22.js} +0 -0
  169. /fides/ui-build/static/admin/_next/static/chunks/{2397-d8161100e3634f2c.js → 2397-c6d0dcb3b921555f.js} +0 -0
  170. /fides/ui-build/static/admin/_next/static/chunks/{3086-be6b52546c3efc90.js → 3086-d099019708303444.js} +0 -0
  171. /fides/ui-build/static/admin/_next/static/chunks/{3855-386aec4f0e0e89f1.js → 3855-4d5d936a58a0dd5f.js} +0 -0
  172. /fides/ui-build/static/admin/_next/static/chunks/{3872-0da2c6a790542bd6.js → 3872-2b2bf5ebd4b0a70f.js} +0 -0
  173. /fides/ui-build/static/admin/_next/static/chunks/{4481-0500c40ed13000c0.js → 4481-f2f57e7a75a90e79.js} +0 -0
  174. /fides/ui-build/static/admin/_next/static/chunks/{5246-9fc6af1a6499e0a4.js → 5246-ac8b0fcb44b00af7.js} +0 -0
  175. /fides/ui-build/static/admin/_next/static/chunks/{5258-3a650be9142cf914.js → 5258-a05dcab2f9315dab.js} +0 -0
  176. /fides/ui-build/static/admin/_next/static/chunks/{5480-f5bec5e881f72f8d.js → 5480-c6c1fb87006e471a.js} +0 -0
  177. /fides/ui-build/static/admin/_next/static/chunks/{5487-d96e1abc93f92631.js → 5487-509639439bf9fb46.js} +0 -0
  178. /fides/ui-build/static/admin/_next/static/chunks/{5826-16e497af363a0cbc.js → 5826-e3970cd9440be33b.js} +0 -0
  179. /fides/ui-build/static/admin/_next/static/chunks/{6315-dee79f6861c94d2d.js → 6315-daf94fa7520fb253.js} +0 -0
  180. /fides/ui-build/static/admin/_next/static/chunks/{6372-f1b54f3cb4888660.js → 6372-41afe1e6a9181cc7.js} +0 -0
  181. /fides/ui-build/static/admin/_next/static/chunks/{6853-2777b5ab5717fada.js → 6853-7f95c36e396d3fb8.js} +0 -0
  182. /fides/ui-build/static/admin/_next/static/chunks/{7751-25e0c1307988ffd7.js → 7751-130668529ab1d0b6.js} +0 -0
  183. /fides/ui-build/static/admin/_next/static/chunks/{79-ba88d0cf4c65aaa2.js → 79-1c326c00cf111c00.js} +0 -0
  184. /fides/ui-build/static/admin/_next/static/chunks/{8433-969280d321d1c3a2.js → 8433-b2a96b825124b596.js} +0 -0
  185. /fides/ui-build/static/admin/_next/static/chunks/{8499-07507004e8275df2.js → 8499-34620330ecf2ac53.js} +0 -0
  186. /fides/ui-build/static/admin/_next/static/chunks/{9046-b18572b89f0aaa92.js → 9046-e7b9a3fd010b01ad.js} +0 -0
  187. /fides/ui-build/static/admin/_next/static/chunks/{9282-1a5a2f6f4d9ed586.js → 9282-6ee061da1eb51d65.js} +0 -0
  188. /fides/ui-build/static/admin/_next/static/chunks/{9999-f2e40d5b13343220.js → 9999-8600f6f495a80b38.js} +0 -0
  189. /fides/ui-build/static/admin/_next/static/chunks/pages/{404-1087258931760074.js → 404-8e0baa6e128803ab.js} +0 -0
  190. /fides/ui-build/static/admin/_next/static/chunks/pages/{ant-poc-b3b4d0a98450ffd1.js → ant-poc-39267961e03be6c5.js} +0 -0
  191. /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-8b9f75fc0f131240.js → privacy-experience-ed38f18c095141fe.js} +0 -0
  192. /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-da37afbe5ec81339.js → privacy-notices-7339b3cdf5d4da32.js} +0 -0
  193. /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-c57b209feef7c2da.js → properties-b5b3196eba90246a.js} +0 -0
  194. /fides/ui-build/static/admin/_next/static/chunks/pages/consent/{reporting-81ca1ac6f52ec342.js → reporting-38b8ec1a221610ff.js} +0 -0
  195. /fides/ui-build/static/admin/_next/static/chunks/pages/{consent-24bef021ee71e36c.js → consent-df2388d953c85c2a.js} +0 -0
  196. /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-6cbd79481199812d.js → [resourceUrn]-5e851b9f27bda8a4.js} +0 -0
  197. /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-46b9790da2fec05a.js → [projectUrn]-9f9112b22fdfb32a.js} +0 -0
  198. /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{projects-742849f39b646a2f.js → projects-ddca867936c89a72.js} +0 -0
  199. /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-e7833c1c606081a9.js → [resourceUrn]-85e3d6f1b2afd3e7.js} +0 -0
  200. /fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{resources-bed368d048ea6883.js → resources-9831226436d884b5.js} +0 -0
  201. /fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/{[monitorId]-25eac2d4008cef3d.js → [monitorId]-5c37c3ad1c3cfba5.js} +0 -0
  202. /fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{activity-0cfa8a9caf7c75c3.js → activity-a0749240265da17d.js} +0 -0
  203. /fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-9cd0c40bef77b120.js → datamap-819ac99e7a56465a.js} +0 -0
  204. /fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/{[...subfieldNames]-ab9bc1a3640547db.js → [...subfieldNames]-259d4a94861afe2b.js} +0 -0
  205. /fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/{[collectionName]-17ec8385bb1fa6d4.js → [collectionName]-25283f5bcac8fa73.js} +0 -0
  206. /fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{[datasetId]-e14c1c07658f8a10.js → [datasetId]-aaedf8f2a849c97f.js} +0 -0
  207. /fides/ui-build/static/admin/_next/static/chunks/pages/{datastore-connection-b8eaa9b9d3832b30.js → datastore-connection-61adfcd5f7f69101.js} +0 -0
  208. /fides/ui-build/static/admin/_next/static/chunks/pages/{index-94e6d589c4edf360.js → index-1072281d6cfe8295.js} +0 -0
  209. /fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-6b032de0a6c2c400.js → [id]-268918d8c1dfe82a.js} +0 -0
  210. /fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-c0d6ae68ff7979c6.js → add-template-cd75949bee7497b6.js} +0 -0
  211. /fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{[id]-bbe5854b7d19b7e9.js → [id]-d1f4178b8a7e2145.js} +0 -0
  212. /fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-4bad69cd42c9722c.js → configure-37e800a20e654064.js} +0 -0
  213. /fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-b4c808a8a0287d11.js → [id]-92145503c4d2d75e.js} +0 -0
  214. /fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-5a701477b006a63b.js → add-property-ab94805694ebd35c.js} +0 -0
  215. /fides/ui-build/static/admin/_next/static/chunks/pages/{properties-9a1899dfe052023e.js → properties-5e623dcd92418638.js} +0 -0
  216. /fides/ui-build/static/admin/_next/static/chunks/pages/reporting/{datamap-449ad3b08750bfc2.js → datamap-710839776b9995ce.js} +0 -0
  217. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{about-d073be113e9ca7b0.js → about-175d39bdd74f148c.js} +0 -0
  218. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{custom-fields-ce9305fa04fecbb8.js → custom-fields-1262d596c0cdcd81.js} +0 -0
  219. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-c5cd5fb578de9515.js → domain-records-f0c6e6034d37dbcf.js} +0 -0
  220. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-39c7ae3602ac69b2.js → email-templates-6ee49492a7769f89.js} +0 -0
  221. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-f35bd2d0c10aa58c.js → locations-deb754d42982562b.js} +0 -0
  222. /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-ba8c25b63bbf7dc2.js → regulations-f9e97decfe56b018.js} +0 -0
  223. /fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-73ef0438c85014bb.js → test-datasets-ae133b6e8e1107f2.js} +0 -0
  224. /fides/ui-build/static/admin/_next/static/chunks/pages/{systems-c320df35d51dc537.js → systems-4d6a17a7a24aca97.js} +0 -0
  225. /fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-181ea5b0ac975239.js → taxonomy-46f47c04a01319cf.js} +0 -0
  226. /fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-622e16a17a11c096.js → [id]-5b752ba934baee94.js} +0 -0
  227. /fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-aa872b21bb835d34.js → user-management-4fbb29cf0a611aae.js} +0 -0
  228. /fides/ui-build/static/admin/_next/static/chunks/{webpack-4df2ba5ee2d40f0a.js → webpack-815e3c35038201da.js} +0 -0
  229. /fides/ui-build/static/admin/_next/static/{NgZHwKJoepGB5-XW8xdZo → lO31cDp9wEzsNdiUnl8It}/_ssgManifest.js +0 -0
fides/_version.py CHANGED
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2025-03-20T13:38:41-0600",
11
+ "date": "2025-03-24T16:32:51-0600",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "22f49c9755a002d9026f5ad9766c3d3aa7162e71",
15
- "version": "2.57.1b6"
14
+ "full-revisionid": "c371f453f33d1af4a35dfe6ae1d78c16b72576d8",
15
+ "version": "2.57.1b8"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -58,8 +58,10 @@ def patch_settings(
58
58
  Only keys provided will be updated, others will be unaffected,
59
59
  i.e. true PATCH behavior.
60
60
  """
61
-
62
- pruned_data = data.model_dump(exclude_none=True)
61
+ # We use exclude_unset=True to ensure that only the provided keys are updated.
62
+ # This is particularly useful for allowing setting a specific key to None, while
63
+ # keeping the existing values for other keys that aren't provided in the payload data.
64
+ pruned_data = data.model_dump(exclude_unset=True)
63
65
  logger.info("PATCHing application settings")
64
66
  update_config: ApplicationConfig = ApplicationConfig.update_api_set(db, pruned_data)
65
67
 
@@ -9,7 +9,7 @@ from fideslang.models import Dataset as FideslangDataset
9
9
  from pydantic import ValidationError as PydanticValidationError
10
10
  from sqlalchemy import not_, select
11
11
  from sqlalchemy.ext.asyncio import AsyncSession
12
- from sqlalchemy.orm import Session
12
+ from sqlalchemy.orm import Session, load_only
13
13
  from starlette import status
14
14
  from starlette.status import (
15
15
  HTTP_200_OK,
@@ -22,9 +22,10 @@ from fides.api.common_exceptions import KeyOrNameAlreadyExists, ValidationError
22
22
  from fides.api.db.base_class import get_key_from_data
23
23
  from fides.api.db.crud import list_resource_query
24
24
  from fides.api.db.ctl_session import get_async_db
25
- from fides.api.models.connectionconfig import ConnectionConfig
25
+ from fides.api.models.connectionconfig import ConnectionConfig, ConnectionType
26
26
  from fides.api.models.datasetconfig import DatasetConfig
27
27
  from fides.api.oauth.utils import verify_oauth_client
28
+ from fides.api.schemas.dataset import DatasetResponse
28
29
  from fides.api.schemas.filter_params import FilterParams
29
30
  from fides.api.schemas.taxonomy_extensions import (
30
31
  DataCategory,
@@ -138,7 +139,7 @@ async def update_dataset(
138
139
  @dataset_router.get(
139
140
  "/dataset",
140
141
  dependencies=[Security(verify_oauth_client, scopes=[CTL_DATASET_READ])],
141
- response_model=Union[Page[FideslangDataset], List[FideslangDataset]],
142
+ response_model=Union[Page[DatasetResponse], List[DatasetResponse]],
142
143
  name="List datasets (optionally paginated)",
143
144
  )
144
145
  async def list_dataset_paginated(
@@ -149,7 +150,9 @@ async def list_dataset_paginated(
149
150
  data_categories: Optional[List[str]] = Query(None),
150
151
  exclude_saas_datasets: Optional[bool] = Query(False),
151
152
  only_unlinked_datasets: Optional[bool] = Query(False),
152
- ) -> Union[Page[FideslangDataset], List[FideslangDataset]]:
153
+ connection_type: Optional[ConnectionType] = Query(None),
154
+ minimal: Optional[bool] = Query(False),
155
+ ) -> Union[Page[DatasetResponse], List[DatasetResponse]]:
153
156
  """
154
157
  Get a list of all of the Datasets.
155
158
  If any pagination parameters (size or page) are provided, then the response will be paginated.
@@ -161,6 +164,25 @@ async def list_dataset_paginated(
161
164
 
162
165
  query = select(CtlDataset)
163
166
 
167
+ if minimal:
168
+ # .options() allows us to modify how the query loads data by configuring the query's loading behavior
169
+ # load_only() optimizes the query by only loading the specified columns from the database
170
+ # This reduces memory usage and query time by not loading unnecessary columns
171
+ # The columns specified below are the minimal set needed for the DatasetResponse model
172
+ query = query.options( # type: ignore[attr-defined]
173
+ load_only(
174
+ CtlDataset.id,
175
+ CtlDataset.fides_key,
176
+ CtlDataset.organization_fides_key,
177
+ CtlDataset.name,
178
+ CtlDataset.created_at,
179
+ CtlDataset.updated_at,
180
+ CtlDataset.meta,
181
+ CtlDataset.fides_meta,
182
+ CtlDataset.description,
183
+ )
184
+ )
185
+
164
186
  # Add filters for search and data categories
165
187
  filter_params = FilterParams(search=search, data_categories=data_categories)
166
188
  filtered_query = apply_filters_to_query(
@@ -170,6 +192,13 @@ async def list_dataset_paginated(
170
192
  filter_params=filter_params,
171
193
  )
172
194
 
195
+ # If applicable, filter by connection type
196
+ if connection_type:
197
+ filtered_query = filtered_query.where(
198
+ CtlDataset.fides_meta["namespace"]["connection_type"].as_string()
199
+ == connection_type.value
200
+ )
201
+
173
202
  # If applicable, keep only unlinked datasets
174
203
  if only_unlinked_datasets:
175
204
  linked_datasets = select([DatasetConfig.ctl_dataset_id])
@@ -187,10 +216,18 @@ async def list_dataset_paginated(
187
216
  )
188
217
 
189
218
  if not page and not size:
190
- return await list_resource_query(db, filtered_query, CtlDataset)
219
+ results = await list_resource_query(db, filtered_query, CtlDataset)
220
+ response = [
221
+ DatasetResponse.model_validate(result.__dict__) for result in results
222
+ ]
223
+ return response
191
224
 
192
225
  pagination_params = Params(page=page or 1, size=size or 50)
193
- return await async_paginate(db, filtered_query, pagination_params)
226
+ results = await async_paginate(db, filtered_query, pagination_params)
227
+ results.items = [ # type: ignore[attr-defined]
228
+ DatasetResponse.model_validate(result.__dict__) for result in results.items # type: ignore[attr-defined]
229
+ ]
230
+ return results
194
231
 
195
232
 
196
233
  @dataset_router.get(
fides/api/main.py CHANGED
@@ -232,10 +232,13 @@ async def log_request(request: Request, call_next: Callable) -> Response:
232
232
  response = Response(status_code=500)
233
233
 
234
234
  handler_time = datetime.now() - start
235
+
236
+ # Take the total time in seconds and convert it to milliseconds, rounding to 3 decimal places
237
+ total_time = round(handler_time.total_seconds() * 1000, 3)
235
238
  logger.bind(
236
239
  method=request.method,
237
240
  status_code=response.status_code,
238
- handler_time=f"{round(handler_time.microseconds * 0.001,3)}ms",
241
+ handler_time=f"{total_time}ms",
239
242
  path=request.url.path,
240
243
  ).info("Request received")
241
244
  return response
@@ -13,12 +13,14 @@ from fides.api.db.base_class import Base
13
13
  from fides.api.models.fides_user import FidesUser # pylint: disable=unused-import
14
14
  from fides.api.models.storage import StorageConfig # pylint: disable=unused-import
15
15
  from fides.api.schemas.storage.storage import StorageDetails, StorageType
16
- from fides.api.tasks.storage import (
17
- LOCAL_FIDES_UPLOAD_DIRECTORY,
16
+ from fides.api.service.storage.s3 import (
18
17
  generic_delete_from_s3,
19
18
  generic_retrieve_from_s3,
19
+ generic_upload_to_s3,
20
+ )
21
+ from fides.api.service.storage.util import (
22
+ LOCAL_FIDES_UPLOAD_DIRECTORY,
20
23
  get_local_filename,
21
- upload_to_s3,
22
24
  )
23
25
 
24
26
 
@@ -91,7 +93,6 @@ class Attachment(Base):
91
93
 
92
94
  user = relationship(
93
95
  "FidesUser",
94
- backref="attachments",
95
96
  lazy="selectin",
96
97
  uselist=False,
97
98
  )
@@ -114,13 +115,10 @@ class Attachment(Base):
114
115
  if self.config.type == StorageType.s3:
115
116
  bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
116
117
  auth_method = self.config.details[StorageDetails.AUTH_METHOD.value]
117
- upload_to_s3(
118
+ generic_upload_to_s3(
118
119
  storage_secrets=self.config.secrets,
119
- data={},
120
120
  bucket_name=bucket_name,
121
121
  file_key=self.id,
122
- resp_format=self.config.format,
123
- privacy_request=None,
124
122
  document=attachment,
125
123
  auth_method=auth_method,
126
124
  )
@@ -1,5 +1,5 @@
1
1
  from enum import Enum as EnumType
2
- from typing import Any
2
+ from typing import TYPE_CHECKING, Any
3
3
 
4
4
  from sqlalchemy import Column
5
5
  from sqlalchemy import Enum as EnumColumn
@@ -8,8 +8,10 @@ from sqlalchemy.ext.declarative import declared_attr
8
8
  from sqlalchemy.orm import Session, relationship
9
9
 
10
10
  from fides.api.db.base_class import Base
11
- from fides.api.models.attachment import Attachment, AttachmentReference
12
- from fides.api.models.fides_user import FidesUser # pylint: disable=unused-import
11
+
12
+ if TYPE_CHECKING:
13
+ from fides.api.models.attachment import Attachment
14
+ from fides.api.models.fides_user import FidesUser
13
15
 
14
16
 
15
17
  class CommentType(str, EnumType):
@@ -78,7 +80,6 @@ class Comment(Base):
78
80
 
79
81
  user = relationship(
80
82
  "FidesUser",
81
- backref="comments",
82
83
  lazy="selectin",
83
84
  uselist=False,
84
85
  )
@@ -90,20 +91,19 @@ class Comment(Base):
90
91
  uselist=True,
91
92
  )
92
93
 
93
- def get_attachments(self, db: Session) -> list[Attachment]:
94
- """Retrieve all attachments associated with this comment."""
95
- stmt = (
96
- db.query(Attachment)
97
- .join(
98
- AttachmentReference, Attachment.id == AttachmentReference.attachment_id
99
- )
100
- .where(AttachmentReference.reference_id == self.id)
101
- )
102
- return db.execute(stmt).scalars().all()
94
+ attachments = relationship(
95
+ "Attachment",
96
+ secondary="attachment_reference",
97
+ primaryjoin="Comment.id == AttachmentReference.reference_id",
98
+ secondaryjoin="Attachment.id == AttachmentReference.attachment_id",
99
+ order_by="Attachment.created_at",
100
+ uselist=True,
101
+ )
103
102
 
104
103
  def delete(self, db: Session) -> None:
105
104
  """Delete the comment and all associated references."""
106
- attachments = self.get_attachments(db)
107
- for attachment in attachments:
108
- attachment.delete(db)
105
+ # Delete the comment
106
+ for attachment in self.attachments:
107
+ if len(attachment.references) == 1:
108
+ attachment.delete(db)
109
109
  db.delete(self)
@@ -186,7 +186,7 @@ class ConnectionConfig(Base):
186
186
  )
187
187
  ),
188
188
  nullable=True,
189
- ) # Type bytea in the db
189
+ ) # Type bytes in the db
190
190
  last_test_timestamp = Column(DateTime(timezone=True))
191
191
  last_test_succeeded = Column(Boolean)
192
192
  disabled = Column(Boolean, server_default="f", default=False)
@@ -39,8 +39,10 @@ from fides.api.graph.config import (
39
39
  CollectionAddress,
40
40
  )
41
41
  from fides.api.migrations.hash_migration_mixin import HashMigrationMixin
42
+ from fides.api.models.attachment import Attachment, AttachmentReference
42
43
  from fides.api.models.audit_log import AuditLog
43
44
  from fides.api.models.client import ClientDetail
45
+ from fides.api.models.comment import Comment, CommentReference
44
46
  from fides.api.models.fides_user import FidesUser
45
47
  from fides.api.models.manual_webhook import AccessManualWebhook
46
48
  from fides.api.models.policy import (
@@ -166,6 +168,20 @@ class PrivacyRequest(
166
168
  Policy,
167
169
  backref="privacy_requests",
168
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
+ )
169
185
  property_id = Column(String, nullable=True)
170
186
 
171
187
  cancel_reason = Column(String(200))
@@ -1011,6 +1027,51 @@ class PrivacyRequest(
1011
1027
  """Return existing Consent Request Tasks for the current privacy request"""
1012
1028
  return self.request_tasks.filter(RequestTask.action_type == ActionType.consent)
1013
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
+
1014
1075
  def get_existing_request_task(
1015
1076
  self,
1016
1077
  db: Session,
fides/api/oauth/utils.py CHANGED
@@ -339,7 +339,16 @@ def has_permissions(
339
339
  has_role: bool = _has_scope_via_role(
340
340
  token_data=token_data, client=client, endpoint_scopes=endpoint_scopes
341
341
  )
342
- return has_direct_scope or has_role
342
+
343
+ has_required_permissions = has_direct_scope or has_role
344
+ if not has_required_permissions:
345
+ scopes_required = ",".join(endpoint_scopes.scopes)
346
+ logger.debug(
347
+ "Authorization failed. Missing required scopes: {}. Neither direct scopes nor role-derived scopes were sufficient.",
348
+ scopes_required,
349
+ )
350
+
351
+ return has_required_permissions
343
352
 
344
353
 
345
354
  def _has_scope_via_role(
@@ -385,16 +394,7 @@ def _has_direct_scopes(
385
394
 
386
395
  def has_scope_subset(user_scopes: List[str], endpoint_scopes: SecurityScopes) -> bool:
387
396
  """Are the required scopes a subset of the scopes belonging to the user?"""
388
- if not set(endpoint_scopes.scopes).issubset(user_scopes):
389
- scopes_required = ",".join(endpoint_scopes.scopes)
390
- scopes_provided = ",".join(user_scopes)
391
- logger.debug(
392
- "Auth token missing required scopes: {}. Scopes provided: {}.",
393
- scopes_required,
394
- scopes_provided,
395
- )
396
- return False
397
- return True
397
+ return set(endpoint_scopes.scopes).issubset(user_scopes)
398
398
 
399
399
 
400
400
  def create_temporary_user_for_login_flow(config: FidesConfig) -> FidesUser:
@@ -1,8 +1,8 @@
1
1
  from typing import Any, Dict, List, Optional, Union
2
2
 
3
- from fideslang.models import Dataset
3
+ from fideslang.models import Dataset, DatasetCollection
4
4
  from fideslang.validation import FidesKey
5
- from pydantic import ConfigDict
5
+ from pydantic import ConfigDict, Field
6
6
 
7
7
  from fides.api.schemas.api import BulkResponse, BulkUpdateFailed
8
8
  from fides.api.schemas.base_class import FidesSchema
@@ -72,3 +72,23 @@ class DatasetReachability(FidesSchema):
72
72
 
73
73
  reachable: bool
74
74
  details: Optional[Union[str, List[Dict[str, Any]]]]
75
+
76
+
77
+ class DatasetResponse(Dataset):
78
+ """
79
+ Dataset response model for API endpoints.
80
+
81
+ Note: This class extends the Dataset model from fideslang rather than having a proper
82
+ dedicated API response model. We had to make the collections field
83
+ Optional and allow null values to support the minimal=true parameter in API responses,
84
+ even though collections is required in the base fideslang Dataset model.
85
+ """
86
+
87
+ collections: Optional[List[DatasetCollection]] = Field( # type: ignore
88
+ description="An array of objects that describe the Dataset's collections.",
89
+ default=None,
90
+ )
91
+
92
+ model_config = ConfigDict(
93
+ extra="ignore", from_attributes=False, coerce_numbers_to_str=True
94
+ )
@@ -67,7 +67,6 @@ from fides.api.tasks import DatabaseTask, celery_app
67
67
  from fides.api.tasks.scheduled.scheduler import scheduler
68
68
  from fides.api.util.collection_util import Row
69
69
  from fides.api.util.logger import Pii, _log_exception, _log_warning
70
- from fides.api.util.logger_context_utils import LoggerContextKeys, log_context
71
70
  from fides.common.api.v1.urn_registry import (
72
71
  PRIVACY_REQUEST_TRANSFER_TO_PARENT,
73
72
  V1_URL_PREFIX,
@@ -270,7 +269,8 @@ def upload_access_results( # pylint: disable=R0912
270
269
 
271
270
 
272
271
  @celery_app.task(base=DatabaseTask, bind=True)
273
- @log_context(capture_args={"privacy_request_id": LoggerContextKeys.privacy_request_id})
272
+ # TODO: Add log_context back in, this is just for some temporary testing
273
+ # @log_context(capture_args={"privacy_request_id": LoggerContextKeys.privacy_request_id})
274
274
  def run_privacy_request(
275
275
  self: DatabaseTask,
276
276
  privacy_request_id: str,
@@ -290,7 +290,10 @@ def run_privacy_request(
290
290
  """
291
291
  resume_step: Optional[CurrentStep] = CurrentStep(from_step) if from_step else None # type: ignore
292
292
  if from_step:
293
- logger.info("Resuming privacy request from checkpoint: '{}'", from_step)
293
+ with logger.contextualize(
294
+ privacy_request_id=privacy_request_id,
295
+ ):
296
+ logger.info("Resuming privacy request from checkpoint: '{}'", from_step)
294
297
 
295
298
  with self.get_new_session() as session:
296
299
  privacy_request = PrivacyRequest.get(db=session, object_id=privacy_request_id)
@@ -302,7 +305,8 @@ def run_privacy_request(
302
305
  with logger.contextualize(
303
306
  privacy_request_source=(
304
307
  privacy_request.source.value if privacy_request.source else None
305
- )
308
+ ),
309
+ privacy_request_id=privacy_request.id,
306
310
  ):
307
311
  if privacy_request.status == PrivacyRequestStatus.canceled:
308
312
  logger.info("Terminating privacy request: request canceled.")
@@ -0,0 +1,133 @@
1
+ from __future__ import annotations
2
+
3
+ from io import BytesIO
4
+ from typing import Any, Dict, Optional
5
+
6
+ from boto3.s3.transfer import TransferConfig
7
+ from botocore.exceptions import ClientError, ParamValidationError
8
+ from fideslang.validation import AnyHttpUrlString
9
+ from loguru import logger
10
+
11
+ from fides.api.schemas.storage.storage import StorageSecrets
12
+ from fides.api.util.aws_util import get_s3_client
13
+ from fides.config import CONFIG
14
+
15
+
16
+ def create_presigned_url_for_s3(
17
+ s3_client: Any, bucket_name: str, file_key: str
18
+ ) -> AnyHttpUrlString:
19
+ """ "Generate a presigned URL to share an S3 object
20
+
21
+ :param s3_client: s3 base client
22
+ :param bucket_name: string
23
+ :param file_key: string
24
+ :return: Presigned URL as string.
25
+ """
26
+ response = s3_client.generate_presigned_url(
27
+ "get_object",
28
+ Params={"Bucket": bucket_name, "Key": file_key},
29
+ ExpiresIn=CONFIG.security.subject_request_download_link_ttl_seconds,
30
+ )
31
+
32
+ # The response contains the presigned URL
33
+ return response
34
+
35
+
36
+ def generic_upload_to_s3( # pylint: disable=R0913
37
+ storage_secrets: Dict[StorageSecrets, Any],
38
+ bucket_name: str,
39
+ file_key: str,
40
+ auth_method: str,
41
+ document: BytesIO,
42
+ ) -> Optional[AnyHttpUrlString]:
43
+ """
44
+ Uploads arbitrary data to S3 returned from an access request.
45
+ Handles both small and large uploads.
46
+ """
47
+ logger.info("Starting S3 Upload of {}", file_key)
48
+
49
+ try:
50
+ s3_client = get_s3_client(auth_method, storage_secrets)
51
+
52
+ # Define a transfer configuration for multipart uploads
53
+ transfer_config = TransferConfig(
54
+ multipart_threshold=5 * 1024 * 1024, # 5 MB threshold for multipart uploads
55
+ multipart_chunksize=5 * 1024 * 1024, # 5 MB chunk size
56
+ )
57
+
58
+ try:
59
+ # Check if the document is a file-like object or raw bytes
60
+ if isinstance(document, bytes):
61
+ document = BytesIO(document) # Wrap raw bytes in a file-like object
62
+
63
+ # Use upload_fileobj for efficient uploads (handles both small and large files)
64
+ s3_client.upload_fileobj(
65
+ Fileobj=document,
66
+ Bucket=bucket_name,
67
+ Key=file_key,
68
+ Config=transfer_config,
69
+ )
70
+ except Exception as e:
71
+ logger.error("Encountered error while uploading S3 object: {}", e)
72
+ raise e
73
+
74
+ # Generate a presigned URL for the uploaded file
75
+ presigned_url: AnyHttpUrlString = create_presigned_url_for_s3(
76
+ s3_client, bucket_name, file_key
77
+ )
78
+
79
+ return presigned_url
80
+ except ClientError as e:
81
+ logger.error(
82
+ "Encountered error while uploading and generating link for S3 object: {}", e
83
+ )
84
+ raise e
85
+ except ParamValidationError as e:
86
+ raise ValueError(f"The parameters you provided are incorrect: {e}")
87
+
88
+
89
+ def generic_retrieve_from_s3(
90
+ storage_secrets: Dict[StorageSecrets, Any],
91
+ bucket_name: str,
92
+ file_key: str,
93
+ auth_method: str,
94
+ ) -> Optional[BytesIO]:
95
+ """Retrieves arbitrary data from s3"""
96
+ logger.info("Starting S3 Retrieve of {}", file_key)
97
+
98
+ try:
99
+ s3_client = get_s3_client(auth_method, storage_secrets)
100
+ try:
101
+ response = s3_client.get_object(Bucket=bucket_name, Key=file_key)
102
+ return response["Body"].read()
103
+ except Exception as e:
104
+ logger.error("Encountered error while retrieving s3 object: {}", e)
105
+ raise e
106
+ except ClientError as e:
107
+ logger.error("Encountered error while retrieving s3 object: {}", e)
108
+ raise e
109
+ except ParamValidationError as e:
110
+ raise ValueError(f"The parameters you provided are incorrect: {e}")
111
+
112
+
113
+ def generic_delete_from_s3(
114
+ storage_secrets: Dict[StorageSecrets, Any],
115
+ bucket_name: str,
116
+ file_key: str,
117
+ auth_method: str,
118
+ ) -> None:
119
+ """Deletes arbitrary data from s3"""
120
+ logger.info("Starting S3 Delete of {}", file_key)
121
+
122
+ try:
123
+ s3_client = get_s3_client(auth_method, storage_secrets)
124
+ try:
125
+ s3_client.delete_object(Bucket=bucket_name, Key=file_key)
126
+ except Exception as e:
127
+ logger.error("Encountered error while deleting s3 object: {}", e)
128
+ raise e
129
+ except ClientError as e:
130
+ logger.error("Encountered error while deleting s3 object: {}", e)
131
+ raise e
132
+ except ParamValidationError as e:
133
+ raise ValueError(f"The parameters you provided are incorrect: {e}")
@@ -0,0 +1,10 @@
1
+ import os
2
+
3
+ LOCAL_FIDES_UPLOAD_DIRECTORY = "fides_uploads"
4
+
5
+
6
+ def get_local_filename(file_key: str) -> str:
7
+ """Verifies that the local storage directory exists"""
8
+ if not os.path.exists(LOCAL_FIDES_UPLOAD_DIRECTORY):
9
+ os.makedirs(LOCAL_FIDES_UPLOAD_DIRECTORY)
10
+ return f"{LOCAL_FIDES_UPLOAD_DIRECTORY}/{file_key}"
@@ -79,7 +79,9 @@ class DatabaseTask(Task): # pylint: disable=W0223
79
79
  # but a new session is instantiated each time the method is invoked
80
80
  # to prevent session overlap when requests are executing concurrently
81
81
  # when in task_always_eager mode (i.e. without proper workers)
82
- return self._sessionmaker()
82
+ new_session = self._sessionmaker()
83
+ logger.debug(f"DatabaseTaskSession ID: {id(new_session)}. Self ID: {id(self)}")
84
+ return new_session
83
85
 
84
86
 
85
87
  def _create_celery(config: FidesConfig = CONFIG) -> Celery: