ethyca-fides 2.68.1b2__py2.py3-none-any.whl → 2.68.1b4__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ethyca-fides might be problematic. Click here for more details.

Files changed (318) hide show
  1. {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/METADATA +3 -1
  2. {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/RECORD +253 -232
  3. fides/_version.py +3 -3
  4. fides/api/alembic/migrations/versions/90502bcda282_update_request_tasks_add_polling_async.py +35 -0
  5. fides/api/alembic/migrations/versions/b1a2c3d4e5f6_add_location_to_privacy_request.py +26 -0
  6. fides/api/api/v1/api.py +2 -0
  7. fides/api/api/v1/endpoints/dsr_package_link.py +167 -0
  8. fides/api/api/v1/endpoints/privacy_request_endpoints.py +31 -1
  9. fides/api/api/v1/endpoints/user_endpoints.py +4 -0
  10. fides/api/common_exceptions.py +12 -3
  11. fides/api/models/detection_discovery/core.py +6 -0
  12. fides/api/models/privacy_request/privacy_request.py +1 -0
  13. fides/api/models/privacy_request/request_task.py +25 -0
  14. fides/api/models/privacy_request/webhook.py +33 -1
  15. fides/api/oauth/utils.py +122 -57
  16. fides/api/schemas/application_config.py +7 -0
  17. fides/api/schemas/connection_configuration/connection_type_system_map.py +6 -0
  18. fides/api/schemas/enums/__init__.py +0 -0
  19. fides/api/schemas/enums/connection_category.py +20 -0
  20. fides/api/schemas/enums/integration_feature.py +23 -0
  21. fides/api/schemas/external_https.py +9 -0
  22. fides/api/schemas/privacy_center_config.py +48 -19
  23. fides/api/schemas/privacy_request.py +16 -0
  24. fides/api/schemas/saas/display_info.py +19 -0
  25. fides/api/schemas/saas/saas_config.py +2 -0
  26. fides/api/schemas/storage/storage.py +4 -0
  27. fides/api/service/async_dsr/__init__.py +0 -0
  28. fides/api/service/async_dsr/async_dsr_service.py +75 -0
  29. fides/api/service/connectors/saas_connector.py +5 -6
  30. fides/api/service/privacy_request/dsr_package/dsr_report_builder.py +6 -4
  31. fides/api/service/privacy_request/request_runner_service.py +41 -4
  32. fides/api/service/privacy_request/request_service.py +50 -2
  33. fides/api/service/storage/storage_uploader_service.py +80 -5
  34. fides/api/service/storage/streaming/__init__.py +42 -0
  35. fides/api/service/storage/streaming/base_storage_client.py +61 -0
  36. fides/api/service/storage/streaming/dsr_storage.py +98 -0
  37. fides/api/service/storage/streaming/retry.py +282 -0
  38. fides/api/service/storage/streaming/s3/__init__.py +5 -0
  39. fides/api/service/storage/streaming/s3/s3_storage_client.py +113 -0
  40. fides/api/service/storage/streaming/s3/streaming_s3.py +196 -0
  41. fides/api/service/storage/streaming/schemas.py +173 -0
  42. fides/api/service/storage/streaming/smart_open_client.py +265 -0
  43. fides/api/service/storage/streaming/smart_open_streaming_storage.py +998 -0
  44. fides/api/service/storage/streaming/storage_client_factory.py +60 -0
  45. fides/api/task/graph_task.py +4 -4
  46. fides/api/task/manual/manual_task_graph_task.py +3 -4
  47. fides/api/util/connection_type.py +20 -0
  48. fides/api/util/text.py +51 -0
  49. fides/common/api/v1/urn_registry.py +3 -0
  50. fides/config/execution_settings.py +4 -0
  51. fides/service/privacy_request/privacy_request_service.py +84 -9
  52. fides/ui-build/static/admin/404.html +1 -1
  53. fides/ui-build/static/admin/_next/static/LRCvfOqg1kP5kGnkD84G4/_buildManifest.js +1 -0
  54. fides/ui-build/static/admin/_next/static/chunks/1099-b973dfdfc5c3de90.js +1 -0
  55. fides/ui-build/static/admin/_next/static/chunks/1345-b60d1f3442379c73.js +1 -0
  56. fides/ui-build/static/admin/_next/static/chunks/{1817-c90365325f8a3d75.js → 1817-74692de5d760a664.js} +1 -1
  57. fides/ui-build/static/admin/_next/static/chunks/{1975.e5cc7a1ccd477671.js → 1975.78e719130cfe3fd6.js} +1 -1
  58. fides/ui-build/static/admin/_next/static/chunks/{2921-46f9465c2852a46b.js → 2921-2d9261e8e2e127c0.js} +1 -1
  59. fides/ui-build/static/admin/_next/static/chunks/3620-ebd89f91b82661e8.js +1 -0
  60. fides/ui-build/static/admin/_next/static/chunks/3729-ccf90cdaae158f39.js +1 -0
  61. fides/ui-build/static/admin/_next/static/chunks/3847-2759bf1f47a1d29e.js +1 -0
  62. fides/ui-build/static/admin/_next/static/chunks/3855-4174a4d4c205d6e8.js +1 -0
  63. fides/ui-build/static/admin/_next/static/chunks/3872-660aba76572c811b.js +1 -0
  64. fides/ui-build/static/admin/_next/static/chunks/{3923-a33633feba5e655e.js → 3923-c6cdc2e5278ae9a7.js} +1 -1
  65. fides/ui-build/static/admin/_next/static/chunks/{401-741bb31b586b7c96.js → 401-8bc2c6c84172c096.js} +1 -1
  66. fides/ui-build/static/admin/_next/static/chunks/{4121-94354b50a41f8497.js → 4121-9a4ebceff9accb7f.js} +1 -1
  67. fides/ui-build/static/admin/_next/static/chunks/431-86ad2beeb93c95c9.js +1 -0
  68. fides/ui-build/static/admin/_next/static/chunks/4608-4d31340b0d0157c1.js +1 -0
  69. fides/ui-build/static/admin/_next/static/chunks/4786-aaef673b30c19e2e.js +1 -0
  70. fides/ui-build/static/admin/_next/static/chunks/4808-a654c7f7a1ca62c8.js +1 -0
  71. fides/ui-build/static/admin/_next/static/chunks/4844-cd7e1d0c7bb94094.js +1 -0
  72. fides/ui-build/static/admin/_next/static/chunks/5258-bc4a25d43e4aa07d.js +1 -0
  73. fides/ui-build/static/admin/_next/static/chunks/5487-37c78c4799ba5223.js +1 -0
  74. fides/ui-build/static/admin/_next/static/chunks/549-2213dc1c34143cda.js +1 -0
  75. fides/ui-build/static/admin/_next/static/chunks/{6084-02abe12327fc3dbc.js → 6084-55cc66e7c94f0686.js} +1 -1
  76. fides/ui-build/static/admin/_next/static/chunks/{6853-270261ef5537a106.js → 6853-313ce974d33432fb.js} +1 -1
  77. fides/ui-build/static/admin/_next/static/chunks/6954-021bd06d0ab59c3c.js +1 -0
  78. fides/ui-build/static/admin/_next/static/chunks/7476-2fc286c2a9125eb8.js +1 -0
  79. fides/ui-build/static/admin/_next/static/chunks/7630-b9a41262a69edf5e.js +1 -0
  80. fides/ui-build/static/admin/_next/static/chunks/768-034e121688a3bbdd.js +1 -0
  81. fides/ui-build/static/admin/_next/static/chunks/{787-5ba991cad1f7664a.js → 787-8df7118742e84908.js} +1 -1
  82. fides/ui-build/static/admin/_next/static/chunks/79-d2ace89108ead8ae.js +1 -0
  83. fides/ui-build/static/admin/_next/static/chunks/796-2de6dac5f311d54a.js +1 -0
  84. fides/ui-build/static/admin/_next/static/chunks/8002-cfdc6574bd841892.js +1 -0
  85. fides/ui-build/static/admin/_next/static/chunks/9046-c44e41da49338c6c.js +1 -0
  86. fides/ui-build/static/admin/_next/static/chunks/9676.b7d5d1d90b9da224.js +1 -0
  87. fides/ui-build/static/admin/_next/static/chunks/{9826-8c81c97a72510fcf.js → 9826-d9addbd5ac990fa4.js} +1 -1
  88. fides/ui-build/static/admin/_next/static/chunks/9951-6ee5c0a23951a07f.js +1 -0
  89. fides/ui-build/static/admin/_next/static/chunks/pages/{404-9174cdb70126c2c5.js → 404-9644eb282f2dcd71.js} +1 -1
  90. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-2c10f6b217b7978b.js → _app-284cba7174fa1f16.js} +136 -135
  91. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-621416493c89ef01.js → manual-42b7fd34712f49bd.js} +1 -1
  92. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-0b9908c3e1dfe49e.js → multiple-4f164eab0960bbe0.js} +1 -1
  93. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-985d3c9179e69d7f.js +1 -0
  94. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-5bb1b31ae8752250.js → add-vendors-61090926e5f98a5d.js} +1 -1
  95. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-17ffe691b91cee2e.js +1 -0
  96. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-4e4d9426743b5cb4.js → [id]-95c13bca5c1e575e.js} +1 -1
  97. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-d72460348fadcab8.js → privacy-experience-609399510a60beb9.js} +1 -1
  98. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-3e7ddc252da00c98.js → [id]-d7d8f228ac74b26e.js} +1 -1
  99. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-35a7c305beee9428.js → new-821c0f82d5a2b7d4.js} +1 -1
  100. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-8365782543cf6ab9.js +1 -0
  101. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-ab96939421639153.js → properties-40a7aa65f4d13cf9.js} +1 -1
  102. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-e4bacfc5c2ed2324.js +1 -0
  103. fides/ui-build/static/admin/_next/static/chunks/pages/{consent-13240e3ca77acfeb.js → consent-70c5c6aa5389d99f.js} +1 -1
  104. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-aad6047a4604b945.js → [resourceUrn]-adc500a03e239857.js} +1 -1
  105. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-bd37b407c80c6986.js → [projectUrn]-3207f62e5012611b.js} +1 -1
  106. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-7b42dee0fb696658.js +1 -0
  107. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-b6b98cea25dd94fa.js → [resourceUrn]-c8b3d090e4ba60d3.js} +1 -1
  108. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-31a45ea2ca2a7f04.js +1 -0
  109. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-6172c2eb539319fd.js +1 -0
  110. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-945d354ff057fb03.js +1 -0
  111. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-d9795e00f39cf4e9.js +1 -0
  112. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-657833fd8528280f.js +1 -0
  113. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-31e6c54794a9883e.js → [resourceUrn]-22eec362dfbb1d2a.js} +1 -1
  114. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-2822a423a7ad0550.js → detection-4decce5ef996e563.js} +1 -1
  115. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-f98dd251babb7e28.js → [resourceUrn]-01acdd1ad492fd89.js} +1 -1
  116. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-56eb4c014f0d96a3.js → discovery-85fdbf4cde60d910.js} +1 -1
  117. fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-8f88dc31c5144ea8.js → datamap-3a4b89fb21d14753.js} +1 -1
  118. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-cb8d303f56091bd5.js +1 -0
  119. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-401c8be76d9daec7.js +1 -0
  120. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-97e2d375b21cfe43.js +1 -0
  121. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-40ef544ca1f2c9b9.js +1 -0
  122. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-e3c763f8e71f8e24.js +1 -0
  123. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-67a7fe58b96ea739.js → [id]-152e5d15705ec072.js} +1 -1
  124. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-651b10cae0e99a05.js +1 -0
  125. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-03c54bc9fb18d2b0.js +1 -0
  126. fides/ui-build/static/admin/_next/static/chunks/pages/{index-876bfd7210040cec.js → index-3d19b9ffa15a928a.js} +1 -1
  127. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-4b0bb4ccfb237d41.js +1 -0
  128. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-78d4e0c14654148b.js +1 -0
  129. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-6e796c3fe632280b.js → [id]-72cb360a6d14e701.js} +1 -1
  130. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-fa0f3841c5bdfdeb.js → add-template-0ed67cf774d5cbf5.js} +1 -1
  131. fides/ui-build/static/admin/_next/static/chunks/pages/messaging-b06a2204e2a5b667.js +1 -0
  132. fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-7050899b3f792129.js +1 -0
  133. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{AntForm-11503454a62d8d7b.js → AntForm-7c3466f4d5797e55.js} +1 -1
  134. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikAntFormItem-a504941807bdb7f1.js → FormikAntFormItem-8de252f25871bab9.js} +1 -1
  135. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikControlled-0119403c8ff97f83.js → FormikControlled-cd6de0da47f980cf.js} +1 -1
  136. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikField-94f6d57d6c94ddf7.js → FormikField-7c238a881fe30e28.js} +1 -1
  137. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{forms-ed1a3ae09d72df89.js → forms-d4f3e8f67f76f146.js} +1 -1
  138. fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-c9220e20c1d93758.js +1 -0
  139. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-b9d6886a3f157120.js +1 -0
  140. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-9c1fd7867b2d80d7.js +1 -0
  141. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-fc959ed21dbce38c.js +1 -0
  142. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-44a4a638dcb2722a.js +1 -0
  143. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-1433c9f9501a884f.js +1 -0
  144. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-41976b28503623cd.js → [id]-16e0b42cb342aa5f.js} +1 -1
  145. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-cb438d8f5ec6007a.js → add-property-ebd114a86b809391.js} +1 -1
  146. fides/ui-build/static/admin/_next/static/chunks/pages/{properties-b6db7036993709b3.js → properties-901be5fa4a48f48c.js} +1 -1
  147. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-da9ced1e20681154.js +1 -0
  148. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-0174554c0ac5958f.js +1 -0
  149. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-6f45ddbf675e66d2.js +1 -0
  150. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-275c49e6089c5c9f.js +1 -0
  151. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-1a8d05e19f06d857.js +1 -0
  152. fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-49d86b9ca4523ca6.js +1 -0
  153. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-386368bf7cb31771.js → domain-records-f71b4b95d91db926.js} +1 -1
  154. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-a595cad18cf04673.js +1 -0
  155. fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-6f7f9751689b042c.js +1 -0
  156. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-b41fb5ad277088ab.js → locations-e2c88d7f779fe604.js} +1 -1
  157. fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-c65acd2b7ab04753.js +1 -0
  158. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-a94dfeea43fbca7d.js → regulations-c1c699eeb40a9dc0.js} +1 -1
  159. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-a274e2191b87e315.js +1 -0
  160. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-18b316e2dad73731.js → [id]-4a48b4f996a64957.js} +1 -1
  161. fides/ui-build/static/admin/_next/static/chunks/pages/systems-30debc87925634d9.js +1 -0
  162. fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-ca625b1296a029f0.js +1 -0
  163. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-3237881945acc0ee.js → [id]-7a3180b235eb8846.js} +1 -1
  164. fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-a3a50d9d79066935.js → user-management-5e2d0acf575252ca.js} +1 -1
  165. fides/ui-build/static/admin/_next/static/chunks/{webpack-69658aeaf6155d89.js → webpack-4502d4d67006b48f.js} +1 -1
  166. fides/ui-build/static/admin/_next/static/css/43d0c0fc207767eb.css +1 -0
  167. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  168. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  169. fides/ui-build/static/admin/add-systems.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-preview.js +1 -1
  208. fides/ui-build/static/admin/lib/fides-tcf.js +2 -2
  209. fides/ui-build/static/admin/login/[provider].html +1 -1
  210. fides/ui-build/static/admin/login.html +1 -1
  211. fides/ui-build/static/admin/messaging/[id].html +1 -1
  212. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  213. fides/ui-build/static/admin/messaging.html +1 -1
  214. fides/ui-build/static/admin/poc/ant-components.html +1 -1
  215. fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
  216. fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
  217. fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
  218. fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
  219. fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
  220. fides/ui-build/static/admin/poc/forms.html +1 -1
  221. fides/ui-build/static/admin/poc/table-migration.html +1 -1
  222. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  223. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  224. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  225. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  226. fides/ui-build/static/admin/privacy-requests.html +1 -1
  227. fides/ui-build/static/admin/properties/[id].html +1 -1
  228. fides/ui-build/static/admin/properties/add-property.html +1 -1
  229. fides/ui-build/static/admin/properties.html +1 -1
  230. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  231. fides/ui-build/static/admin/settings/about/alpha.html +1 -1
  232. fides/ui-build/static/admin/settings/about.html +1 -1
  233. fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
  234. fides/ui-build/static/admin/settings/consent.html +1 -1
  235. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  236. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  237. fides/ui-build/static/admin/settings/domains.html +1 -1
  238. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  239. fides/ui-build/static/admin/settings/locations.html +1 -1
  240. fides/ui-build/static/admin/settings/organization.html +1 -1
  241. fides/ui-build/static/admin/settings/regulations.html +1 -1
  242. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  243. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  244. fides/ui-build/static/admin/systems.html +1 -1
  245. fides/ui-build/static/admin/taxonomy.html +1 -1
  246. fides/ui-build/static/admin/user-management/new.html +1 -1
  247. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  248. fides/ui-build/static/admin/user-management.html +1 -1
  249. fides/ui-build/static/admin/_next/static/chunks/203-0c6cadcda98bdd33.js +0 -1
  250. fides/ui-build/static/admin/_next/static/chunks/3450-9314e1b15df8a8da.js +0 -1
  251. fides/ui-build/static/admin/_next/static/chunks/3855-4267fd8193e7f525.js +0 -1
  252. fides/ui-build/static/admin/_next/static/chunks/3872-ac5feefd40b61ae3.js +0 -1
  253. fides/ui-build/static/admin/_next/static/chunks/409-5bc4369b80a8c11d.js +0 -1
  254. fides/ui-build/static/admin/_next/static/chunks/4230-1ebc8c0ab293a077.js +0 -1
  255. fides/ui-build/static/admin/_next/static/chunks/431-a34d7ceff17c2169.js +0 -1
  256. fides/ui-build/static/admin/_next/static/chunks/4608-557fb24665b2e4bf.js +0 -1
  257. fides/ui-build/static/admin/_next/static/chunks/5309-ffdec884eec79d29.js +0 -1
  258. fides/ui-build/static/admin/_next/static/chunks/5574-831167a8da90e2e6.js +0 -1
  259. fides/ui-build/static/admin/_next/static/chunks/6662-499c189f932a35aa.js +0 -1
  260. fides/ui-build/static/admin/_next/static/chunks/6780-7d28e030f6516e5d.js +0 -1
  261. fides/ui-build/static/admin/_next/static/chunks/6882-7cc1d14e27a80c10.js +0 -1
  262. fides/ui-build/static/admin/_next/static/chunks/6954-7784e8d5ad6b8110.js +0 -1
  263. fides/ui-build/static/admin/_next/static/chunks/7476-4de465016d3433b4.js +0 -1
  264. fides/ui-build/static/admin/_next/static/chunks/7630-2a5c57787632693d.js +0 -1
  265. fides/ui-build/static/admin/_next/static/chunks/7725-c79513b04113112b.js +0 -1
  266. fides/ui-build/static/admin/_next/static/chunks/79-98cfab20bb831137.js +0 -1
  267. fides/ui-build/static/admin/_next/static/chunks/796-0b768155bf20505f.js +0 -1
  268. fides/ui-build/static/admin/_next/static/chunks/8735-f84afcc50885883c.js +0 -1
  269. fides/ui-build/static/admin/_next/static/chunks/9046-97a972cc8a8ed24d.js +0 -1
  270. fides/ui-build/static/admin/_next/static/chunks/9226-318dadf1c050ecda.js +0 -1
  271. fides/ui-build/static/admin/_next/static/chunks/9676.9e6828b42ef05e06.js +0 -1
  272. fides/ui-build/static/admin/_next/static/chunks/9951-4df2b67e0def5500.js +0 -1
  273. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-18e96ce81dab51a4.js +0 -1
  274. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-54d7c7310763c66d.js +0 -1
  275. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-6bc3b73a21576869.js +0 -1
  276. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-fe3d6887fecf0f86.js +0 -1
  277. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-e4770acf7044e2f5.js +0 -1
  278. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-0db635c3483c9da8.js +0 -1
  279. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-0c0e0a7798345541.js +0 -1
  280. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-3c56e5fe072a44c6.js +0 -1
  281. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-58827eb86516931f.js +0 -1
  282. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-6a90131dcecd694c.js +0 -1
  283. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-145fe9e4cfcb231d.js +0 -1
  284. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-8a1e5d140785c1e9.js +0 -1
  285. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-227b5db4b472a6a7.js +0 -1
  286. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-8401f17fe5d9a1dc.js +0 -1
  287. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-7d77b3ad069be268.js +0 -1
  288. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-90a8df230cb89877.js +0 -1
  289. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-cfb25b02abb8da71.js +0 -1
  290. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-4e286a1e501a0c73.js +0 -1
  291. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-3fdc55d4c129e618.js +0 -1
  292. fides/ui-build/static/admin/_next/static/chunks/pages/messaging-8f9c006b6166f002.js +0 -1
  293. fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-6ba7ae4f26c06cb0.js +0 -1
  294. fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-e8db3ad525e7ddbd.js +0 -1
  295. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-c14dd24592369467.js +0 -1
  296. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-100d7d03930629a8.js +0 -1
  297. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-6f8d1b3ec83cfcf0.js +0 -1
  298. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-3ce15577435d47cb.js +0 -1
  299. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-709bcb0bc6a5382d.js +0 -1
  300. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-4bc3e281409265cc.js +0 -1
  301. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-1ea40fcd6b4268bf.js +0 -1
  302. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-65c7600fadc6e55a.js +0 -1
  303. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-33dab986141b3663.js +0 -1
  304. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-1195042727c399ed.js +0 -1
  305. fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-71b98858ecb4e097.js +0 -1
  306. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-cf427e04f862b5d2.js +0 -1
  307. fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-eabeeec5bf2773c6.js +0 -1
  308. fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-ee56698ae3a6a78b.js +0 -1
  309. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-0e2e98cc38ee5499.js +0 -1
  310. fides/ui-build/static/admin/_next/static/chunks/pages/systems-c32589c86081b750.js +0 -1
  311. fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-a8f09bf8f3204ca7.js +0 -1
  312. fides/ui-build/static/admin/_next/static/css/a72179b1754aadd3.css +0 -1
  313. fides/ui-build/static/admin/_next/static/qvk5eMANVfwYkdURE7fgG/_buildManifest.js +0 -1
  314. {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/WHEEL +0 -0
  315. {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/entry_points.txt +0 -0
  316. {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/licenses/LICENSE +0 -0
  317. {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/top_level.txt +0 -0
  318. /fides/ui-build/static/admin/_next/static/{qvk5eMANVfwYkdURE7fgG → LRCvfOqg1kP5kGnkD84G4}/_ssgManifest.js +0 -0
@@ -0,0 +1,282 @@
1
+ from __future__ import annotations
2
+
3
+ import random
4
+ import time
5
+ from functools import wraps
6
+ from typing import Any, Callable, Optional, Type
7
+
8
+ from loguru import logger
9
+
10
+ from fides.config import CONFIG
11
+
12
+
13
+ class RetryableError(Exception):
14
+ """Base exception for errors that should trigger retries."""
15
+
16
+
17
+ class TransientError(RetryableError):
18
+ """Exception for transient errors that should be retried."""
19
+
20
+
21
+ class PermanentError(RetryableError):
22
+ """Exception for permanent errors that should not be retried."""
23
+
24
+
25
+ class RetryConfig:
26
+ """Configuration for retry behavior."""
27
+
28
+ def __init__(
29
+ self,
30
+ max_retries: int = 3,
31
+ base_delay: float = 1.0,
32
+ max_delay: float = 60.0,
33
+ backoff_factor: float = 2.0,
34
+ jitter: bool = True,
35
+ retry_on_exceptions: Optional[tuple[Type[Exception], ...]] = None,
36
+ ):
37
+ self.max_retries = max_retries
38
+ self.base_delay = base_delay
39
+ self.max_delay = max_delay
40
+ self.backoff_factor = backoff_factor
41
+ self.jitter = jitter
42
+ self.retry_on_exceptions = retry_on_exceptions or (Exception,)
43
+
44
+
45
+ def is_transient_error(error: Exception) -> bool:
46
+ """
47
+ Determine if an error is transient and should be retried.
48
+
49
+ This is a cloud-agnostic implementation that can be extended
50
+ with provider-specific logic.
51
+ """
52
+ # Check if this is our custom TransientError
53
+ if isinstance(error, TransientError):
54
+ return True
55
+
56
+ error_str = str(error).lower()
57
+
58
+ # Common transient error patterns across cloud providers
59
+ transient_patterns = [
60
+ "timeout",
61
+ "timed out",
62
+ "connection",
63
+ "network",
64
+ "temporary",
65
+ "throttling",
66
+ "rate limit",
67
+ "too many requests",
68
+ "service unavailable",
69
+ "internal server error",
70
+ "bad gateway",
71
+ "gateway timeout",
72
+ "request timeout",
73
+ "connection reset",
74
+ "broken pipe",
75
+ ]
76
+
77
+ return any(pattern in error_str for pattern in transient_patterns)
78
+
79
+
80
+ def calculate_backoff_delay(
81
+ attempt: int,
82
+ base_delay: float,
83
+ max_delay: float,
84
+ backoff_factor: float,
85
+ jitter: bool = True,
86
+ ) -> float:
87
+ """
88
+ Calculate exponential backoff delay with optional jitter.
89
+
90
+ Args:
91
+ attempt: Current attempt number (0-based)
92
+ base_delay: Base delay in seconds
93
+ max_delay: Maximum delay in seconds
94
+ backoff_factor: Multiplier for each attempt
95
+ jitter: Whether to add random jitter to prevent thundering herd
96
+
97
+ Returns:
98
+ Delay in seconds before next retry
99
+ """
100
+ if attempt == 0:
101
+ return 0
102
+
103
+ # Exponential backoff: base_delay * (backoff_factor ^ attempt)
104
+ delay = base_delay * (backoff_factor ** (attempt - 1))
105
+
106
+ # Cap at maximum delay
107
+ delay = min(delay, max_delay)
108
+
109
+ # Add jitter to prevent multiple retries from synchronizing
110
+ if jitter:
111
+ jitter_amount = delay * 0.1 # 10% jitter
112
+ delay += random.uniform(-jitter_amount, jitter_amount)
113
+ delay = max(0, delay) # Ensure non-negative
114
+
115
+ return delay
116
+
117
+
118
+ def retry_with_backoff(
119
+ retry_config: Optional[RetryConfig] = None,
120
+ operation_name: str = "operation",
121
+ ) -> Callable:
122
+ """
123
+ Decorator for retrying operations with exponential backoff.
124
+
125
+ This is a cloud-agnostic retry mechanism that can be extended
126
+ with provider-specific retry logic.
127
+
128
+ Args:
129
+ retry_config: Configuration for retry behavior
130
+ operation_name: Name of the operation for logging
131
+
132
+ Returns:
133
+ Decorated function with retry logic
134
+ """
135
+ if retry_config is None:
136
+ # Use default configuration from settings
137
+ settings = CONFIG.execution
138
+ retry_config = RetryConfig(
139
+ max_retries=settings.task_retry_count,
140
+ base_delay=settings.task_retry_delay,
141
+ backoff_factor=settings.task_retry_backoff,
142
+ )
143
+
144
+ def decorator(func: Callable) -> Callable:
145
+ @wraps(func)
146
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
147
+ last_exception: Optional[Exception] = None
148
+
149
+ for attempt in range(retry_config.max_retries + 1):
150
+ try:
151
+ # Track retry attempts
152
+ if attempt > 0:
153
+ logger.debug(
154
+ "Retry attempt {}/{} for {}",
155
+ attempt,
156
+ retry_config.max_retries,
157
+ operation_name,
158
+ )
159
+
160
+ return func(*args, **kwargs)
161
+
162
+ except Exception as e:
163
+ last_exception = e
164
+
165
+ # Check if this is a permanent error that shouldn't be retried
166
+ if isinstance(e, PermanentError):
167
+ logger.error(
168
+ "Permanent error in {}: {}. Not retrying.",
169
+ operation_name,
170
+ e,
171
+ )
172
+ raise
173
+
174
+ # Check if we should retry this error
175
+ should_retry = (
176
+ attempt < retry_config.max_retries
177
+ and isinstance(e, retry_config.retry_on_exceptions)
178
+ and is_transient_error(e)
179
+ )
180
+
181
+ if not should_retry:
182
+ logger.error(
183
+ "Non-retryable error in {}: {}. Not retrying.",
184
+ operation_name,
185
+ e,
186
+ )
187
+ raise
188
+
189
+ # Calculate delay for next retry
190
+ delay = calculate_backoff_delay(
191
+ attempt + 1,
192
+ retry_config.base_delay,
193
+ retry_config.max_delay,
194
+ retry_config.backoff_factor,
195
+ retry_config.jitter,
196
+ )
197
+
198
+ logger.warning(
199
+ "Transient error in {} (attempt {}/{}): {}. "
200
+ "Retrying in {:.1f} seconds...",
201
+ operation_name,
202
+ attempt + 1,
203
+ retry_config.max_retries + 1,
204
+ e,
205
+ delay,
206
+ )
207
+
208
+ # Sleep before retry
209
+ time.sleep(delay)
210
+
211
+ # If we get here, all retries were exhausted
212
+ logger.error(
213
+ "Operation {} failed after {} retry attempts. Last error: {}",
214
+ operation_name,
215
+ retry_config.max_retries,
216
+ last_exception,
217
+ )
218
+ if last_exception is not None:
219
+ raise last_exception
220
+
221
+ raise RuntimeError(
222
+ f"Operation {operation_name} failed after {retry_config.max_retries} retry attempts"
223
+ )
224
+
225
+ return wrapper
226
+
227
+ return decorator
228
+
229
+
230
+ def retry_cloud_storage_operation(
231
+ provider: str = "cloud storage",
232
+ operation_name: str = "storage operation",
233
+ max_retries: int = 3,
234
+ base_delay: float = 1.0,
235
+ max_delay: float = 60.0,
236
+ backoff_factor: float = 2.0,
237
+ ) -> Callable:
238
+ """
239
+ Cloud-agnostic retry decorator for storage operations.
240
+
241
+ This decorator provides retry logic that works across different
242
+ cloud storage providers while allowing provider-specific optimizations.
243
+
244
+ Args:
245
+ provider: Name of the cloud storage provider
246
+ operation_name: Name of the storage operation
247
+ max_retries: Maximum number of retry attempts
248
+ base_delay: Base delay in seconds
249
+ max_delay: Maximum delay in seconds
250
+ backoff_factor: Multiplier for each attempt
251
+
252
+ Returns:
253
+ Decorated function with cloud-agnostic retry logic
254
+ """
255
+ retry_config = RetryConfig(
256
+ max_retries=max_retries,
257
+ base_delay=base_delay,
258
+ max_delay=max_delay,
259
+ backoff_factor=backoff_factor,
260
+ jitter=True,
261
+ )
262
+
263
+ return retry_with_backoff(
264
+ retry_config=retry_config, operation_name=f"{provider} {operation_name}"
265
+ )
266
+
267
+
268
+ def create_retry_config_from_settings() -> RetryConfig:
269
+ """
270
+ Create a RetryConfig instance from application settings.
271
+
272
+ Returns:
273
+ RetryConfig configured with application defaults
274
+ """
275
+ settings = CONFIG.execution
276
+ return RetryConfig(
277
+ max_retries=settings.task_retry_count,
278
+ base_delay=settings.task_retry_delay,
279
+ backoff_factor=settings.task_retry_backoff,
280
+ max_delay=60.0, # Cap at 1 minute
281
+ jitter=True,
282
+ )
@@ -0,0 +1,5 @@
1
+ """S3 streaming storage package."""
2
+
3
+ from .s3_storage_client import S3StorageClient
4
+
5
+ __all__ = ["S3StorageClient"]
@@ -0,0 +1,113 @@
1
+ """S3-specific storage client implementation."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from typing import Any, Optional
6
+
7
+ from fideslang.validation import AnyHttpUrlString
8
+ from loguru import logger
9
+
10
+ from fides.api.schemas.storage.storage import AWSAuthMethod, StorageSecrets
11
+ from fides.api.service.storage.s3 import create_presigned_url_for_s3
12
+ from fides.api.service.storage.streaming.base_storage_client import BaseStorageClient
13
+ from fides.api.util.aws_util import get_s3_client
14
+
15
+
16
+ class S3StorageClient(BaseStorageClient):
17
+ """S3-specific storage client implementation.
18
+
19
+ Handles S3-specific URI construction, transport parameters, and presigned URL
20
+ generation for the smart-open storage client.
21
+ """
22
+
23
+ def __init__(self, storage_secrets: dict[StorageSecrets, Any]):
24
+ """Initialize the storage client with secrets.
25
+
26
+ Args:
27
+ storage_secrets: Provider-specific storage credentials and configuration using StorageSecrets enum keys
28
+ """
29
+ super().__init__(storage_secrets)
30
+ self.storage_secrets: dict[StorageSecrets, Any] = storage_secrets
31
+
32
+ def build_uri(self, bucket: str, key: str) -> str:
33
+ """Build the S3 URI for the storage location.
34
+
35
+ Args:
36
+ bucket: S3 bucket name
37
+ key: Object key/path
38
+
39
+ Returns:
40
+ S3 URI string for smart-open
41
+ """
42
+ # Handle custom endpoint (e.g., MinIO) - endpoint_url is not in StorageSecrets enum
43
+ # For now, we'll use standard S3 URI since we only have enum keys
44
+ return f"s3://{bucket}/{key}"
45
+
46
+ def get_transport_params(self) -> dict[str, Any]:
47
+ """Get S3-specific transport parameters for smart-open.
48
+
49
+ Returns:
50
+ Dictionary of S3 transport parameters for smart-open
51
+ """
52
+ params = {}
53
+
54
+ if StorageSecrets.AWS_ACCESS_KEY_ID in self.storage_secrets:
55
+ params["access_key"] = self.storage_secrets[
56
+ StorageSecrets.AWS_ACCESS_KEY_ID
57
+ ]
58
+ if StorageSecrets.AWS_SECRET_ACCESS_KEY in self.storage_secrets:
59
+ params["secret_key"] = self.storage_secrets[
60
+ StorageSecrets.AWS_SECRET_ACCESS_KEY
61
+ ]
62
+ if StorageSecrets.REGION_NAME in self.storage_secrets:
63
+ params["region"] = self.storage_secrets[StorageSecrets.REGION_NAME]
64
+ if StorageSecrets.AWS_ASSUME_ROLE in self.storage_secrets:
65
+ params["assume_role_arn"] = self.storage_secrets[
66
+ StorageSecrets.AWS_ASSUME_ROLE
67
+ ]
68
+
69
+ return params
70
+
71
+ def generate_presigned_url(
72
+ self, bucket: str, key: str, ttl_seconds: Optional[int] = None
73
+ ) -> AnyHttpUrlString:
74
+ """Generate an S3 presigned URL for the object.
75
+
76
+ Args:
77
+ bucket: S3 bucket name
78
+ key: Object key/path
79
+ ttl_seconds: Time to live in seconds
80
+
81
+ Returns:
82
+ S3 presigned URL for the object
83
+
84
+ Raises:
85
+ Exception: If presigned URL generation fails
86
+ """
87
+ try:
88
+ # Storage secrets are already in the right format for get_s3_client
89
+ # get_s3_client expects dict[StorageSecrets, Any] with enum keys
90
+ s3_secrets = self.storage_secrets
91
+
92
+ # Determine auth method based on available credentials
93
+ # If AWS credentials are present, use SECRET_KEYS, otherwise use AUTOMATIC
94
+ if (
95
+ StorageSecrets.AWS_ACCESS_KEY_ID in self.storage_secrets
96
+ and StorageSecrets.AWS_SECRET_ACCESS_KEY in self.storage_secrets
97
+ and self.storage_secrets[StorageSecrets.AWS_ACCESS_KEY_ID]
98
+ and self.storage_secrets[StorageSecrets.AWS_SECRET_ACCESS_KEY]
99
+ ):
100
+ auth_method = AWSAuthMethod.SECRET_KEYS.value
101
+ else:
102
+ auth_method = AWSAuthMethod.AUTOMATIC.value
103
+
104
+ # Extract assume_role_arn if present for role assumption
105
+ assume_role_arn = None
106
+ if StorageSecrets.AWS_ASSUME_ROLE in self.storage_secrets:
107
+ assume_role_arn = self.storage_secrets[StorageSecrets.AWS_ASSUME_ROLE]
108
+
109
+ s3_client = get_s3_client(auth_method, s3_secrets, assume_role_arn)
110
+ return create_presigned_url_for_s3(s3_client, bucket, key, ttl_seconds)
111
+ except Exception as e:
112
+ logger.error(f"Failed to generate S3 presigned URL: {e}")
113
+ raise
@@ -0,0 +1,196 @@
1
+ from __future__ import annotations
2
+
3
+ from io import BytesIO
4
+ from typing import Any, Optional, Union
5
+
6
+ from fideslang.validation import AnyHttpUrlString
7
+ from loguru import logger
8
+
9
+ from fides.api.common_exceptions import StorageUploadError
10
+ from fides.api.models.privacy_request import PrivacyRequest
11
+ from fides.api.schemas.storage.storage import StorageSecrets, StorageSecretsS3
12
+ from fides.api.service.storage.s3 import generic_upload_to_s3
13
+ from fides.api.service.storage.streaming.retry import retry_cloud_storage_operation
14
+ from fides.api.service.storage.streaming.schemas import StorageUploadConfig
15
+ from fides.api.service.storage.streaming.smart_open_client import SmartOpenStorageClient
16
+ from fides.api.service.storage.streaming.smart_open_streaming_storage import (
17
+ SmartOpenStreamingStorage,
18
+ )
19
+
20
+
21
+ @retry_cloud_storage_operation(
22
+ provider="s3_streaming",
23
+ operation_name="upload_to_s3_streaming",
24
+ max_retries=2,
25
+ base_delay=2.0,
26
+ max_delay=30.0,
27
+ )
28
+ def upload_to_s3_streaming(
29
+ storage_secrets: Union[StorageSecretsS3, dict[StorageSecrets, Any]],
30
+ data: dict,
31
+ bucket_name: str,
32
+ file_key: str,
33
+ resp_format: str,
34
+ privacy_request: PrivacyRequest,
35
+ document: Optional[BytesIO],
36
+ auth_method: str,
37
+ max_workers: int = 5,
38
+ ) -> Optional[AnyHttpUrlString]:
39
+ """Uploads arbitrary data to S3 using smart-open streaming for memory efficiency.
40
+
41
+ This function now uses smart-open for efficient cloud storage operations while maintaining
42
+ our DSR-specific business logic for package splitting and attachment processing.
43
+ """
44
+ formatted_secrets = format_secrets(storage_secrets)
45
+
46
+ if document is not None:
47
+ _, response = generic_upload_to_s3(
48
+ formatted_secrets, # type: ignore[arg-type]
49
+ bucket_name,
50
+ file_key,
51
+ auth_method,
52
+ document,
53
+ )
54
+ return response
55
+
56
+ try:
57
+ storage_client = SmartOpenStorageClient("s3", formatted_secrets)
58
+
59
+ # Create upload config for the streaming interface
60
+ upload_config = StorageUploadConfig(
61
+ bucket_name=bucket_name,
62
+ file_key=file_key,
63
+ resp_format=resp_format,
64
+ max_workers=max_workers,
65
+ )
66
+
67
+ # Use the smart-open streaming implementation
68
+ streaming_storage = SmartOpenStreamingStorage(storage_client)
69
+ result = streaming_storage.upload_to_storage_streaming(
70
+ data,
71
+ upload_config,
72
+ privacy_request,
73
+ document,
74
+ )
75
+
76
+ logger.debug(
77
+ "Successfully uploaded streaming archive to S3 using smart-open: {}",
78
+ file_key,
79
+ )
80
+ return result
81
+
82
+ except Exception as e:
83
+ logger.error("Unexpected error during smart-open streaming upload: {}", e)
84
+ raise StorageUploadError(
85
+ f"Unexpected error during smart-open streaming upload: {e}"
86
+ )
87
+
88
+
89
+ def _process_storage_secrets_input(
90
+ storage_secrets: Union[StorageSecretsS3, dict[StorageSecrets, Any]] # type: ignore[misc]
91
+ ) -> dict[str, Any]:
92
+ """Process input and convert to string-keyed dictionary."""
93
+ final_secrets: dict[str, Any] = {}
94
+
95
+ if isinstance(storage_secrets, StorageSecretsS3):
96
+ # Convert StorageSecretsS3 model directly to string keys
97
+ for key, value in storage_secrets.model_dump().items():
98
+ if value is not None:
99
+ final_secrets[key] = value
100
+ else:
101
+ # Process dict input, converting enum keys to strings if needed
102
+ for key, value in (storage_secrets or {}).items(): # type: ignore[assignment]
103
+ if isinstance(key, str):
104
+ final_secrets[key] = value
105
+ elif isinstance(key, StorageSecrets):
106
+ final_secrets[key.value] = value
107
+
108
+ return final_secrets
109
+
110
+
111
+ def _validate_aws_credentials(final_secrets: dict[str, Any]) -> None:
112
+ """Validate that required AWS credentials are present."""
113
+ has_access_key = (
114
+ "aws_access_key_id" in final_secrets and final_secrets["aws_access_key_id"]
115
+ )
116
+ has_secret_key = (
117
+ "aws_secret_access_key" in final_secrets
118
+ and final_secrets["aws_secret_access_key"]
119
+ )
120
+
121
+ # If we have any AWS credentials, we need both for SECRET_KEYS auth
122
+ if has_access_key or has_secret_key:
123
+ if not has_access_key:
124
+ raise ValueError(
125
+ "Missing required AWS credentials for SECRET_KEYS auth: aws_access_key_id. "
126
+ "Storage configuration must include valid AWS access key and secret key."
127
+ )
128
+ if not has_secret_key:
129
+ raise ValueError(
130
+ "Missing required AWS credentials for SECRET_KEYS auth: aws_secret_access_key. "
131
+ "Storage configuration must include valid AWS access key and secret key."
132
+ )
133
+ else:
134
+ # AUTOMATIC authentication - check if region is provided
135
+ has_region = "region_name" in final_secrets and final_secrets["region_name"]
136
+ if not has_region:
137
+ raise ValueError(
138
+ "Missing required region_name for AUTOMATIC authentication. "
139
+ "Storage configuration must include a valid AWS region."
140
+ )
141
+
142
+
143
+ def _set_default_region(final_secrets: dict[str, Any]) -> None:
144
+ """Set default region if missing."""
145
+ if "region_name" not in final_secrets or not final_secrets["region_name"]:
146
+ logger.debug("Setting default region to 'us-east-1'")
147
+ final_secrets["region_name"] = "us-east-1"
148
+
149
+
150
+ def format_secrets(
151
+ storage_secrets: Union[StorageSecretsS3, dict[StorageSecrets, Any]] # type: ignore[misc]
152
+ ) -> dict[str, Any]:
153
+ """
154
+ Returns the correct format for the S3StorageClient.
155
+
156
+ This function handles multiple credential formats and processes them through several stages:
157
+ 1. Input processing: Accepts either StorageSecretsS3 models (from API) or raw dicts (from database)
158
+ 2. Key normalization: Converts all keys to string format for consistency
159
+ 3. Validation: Ensures required AWS credentials are present based on auth method
160
+ 4. Default setting: Sets default region if missing (after validation)
161
+ 5. Return: Returns string-keyed dict ready for S3StorageClient
162
+
163
+ Input formats:
164
+ - StorageSecretsS3: Used by storage API endpoints (e.g., put_config_secrets)
165
+ - dict[StorageSecrets, Any]: Used by storage models (e.g., StorageConfig.secrets)
166
+ - dict[str, Any]: Used by database queries (e.g., StorageConfig.get_by)
167
+
168
+ Authentication methods:
169
+ - SECRET_KEYS: Requires aws_access_key_id, aws_secret_access_key, and region_name
170
+ - AUTOMATIC: Requires only region_name (relies on AWS SDK credential chain)
171
+ - Role assumption: Can be used with either auth method via assume_role_arn
172
+
173
+ Output format:
174
+ - dict[str, Any]: Required by S3StorageClient.generate_presigned_url() and other AWS operations
175
+
176
+ Returns:
177
+ dict[str, Any]: Credentials with string keys like 'aws_access_key_id'
178
+
179
+ Raises:
180
+ ValueError: If required AWS credentials are missing for the chosen auth method
181
+ """
182
+ logger.debug("format_secrets called with type: {}", type(storage_secrets).__name__)
183
+
184
+ # Stage 1: Process input and create final format directly
185
+ final_secrets = _process_storage_secrets_input(storage_secrets)
186
+
187
+ # Stage 2: Validate required credentials BEFORE setting defaults
188
+ _validate_aws_credentials(final_secrets)
189
+
190
+ # Stage 3: Set default region if missing (after validation)
191
+ _set_default_region(final_secrets)
192
+
193
+ logger.debug(
194
+ "format_secrets completed successfully with {} keys", len(final_secrets)
195
+ )
196
+ return final_secrets