ethyca-fides 2.68.1b3__py2.py3-none-any.whl → 2.69.0__py2.py3-none-any.whl

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

Potentially problematic release.


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

Files changed (271) hide show
  1. {ethyca_fides-2.68.1b3.dist-info → ethyca_fides-2.69.0.dist-info}/METADATA +1 -1
  2. {ethyca_fides-2.68.1b3.dist-info → ethyca_fides-2.69.0.dist-info}/RECORD +249 -243
  3. fides/_version.py +3 -3
  4. fides/api/alembic/migrations/versions/b1a2c3d4e5f6_add_location_to_privacy_request.py +26 -0
  5. fides/api/api/v1/api.py +2 -0
  6. fides/api/api/v1/endpoints/dsr_package_link.py +169 -0
  7. fides/api/api/v1/endpoints/oauth_endpoints.py +1 -0
  8. fides/api/api/v1/endpoints/privacy_request_endpoints.py +32 -1
  9. fides/api/api/v1/endpoints/user_endpoints.py +4 -0
  10. fides/api/models/privacy_request/privacy_request.py +1 -0
  11. fides/api/models/privacy_request/webhook.py +33 -1
  12. fides/api/oauth/utils.py +118 -50
  13. fides/api/schemas/application_config.py +7 -0
  14. fides/api/schemas/connection_configuration/connection_type_system_map.py +6 -0
  15. fides/api/schemas/enums/__init__.py +0 -0
  16. fides/api/schemas/enums/connection_category.py +20 -0
  17. fides/api/schemas/enums/integration_feature.py +26 -0
  18. fides/api/schemas/external_https.py +9 -0
  19. fides/api/schemas/privacy_request.py +16 -0
  20. fides/api/schemas/saas/connector_template.py +5 -0
  21. fides/api/schemas/saas/display_info.py +19 -0
  22. fides/api/schemas/saas/saas_config.py +2 -0
  23. fides/api/schemas/storage/storage.py +2 -0
  24. fides/api/service/connectors/saas/connector_registry_service.py +7 -0
  25. fides/api/service/privacy_request/dsr_package/dsr_report_builder.py +253 -71
  26. fides/api/service/privacy_request/dsr_package/templates/attachments_index.html +4 -2
  27. fides/api/service/privacy_request/dsr_package/templates/collection_index.html +3 -1
  28. fides/api/service/privacy_request/dsr_package/templates/dataset_index.html +1 -1
  29. fides/api/service/privacy_request/request_runner_service.py +52 -6
  30. fides/api/service/privacy_request/request_service.py +18 -1
  31. fides/api/service/storage/storage_uploader_service.py +1 -21
  32. fides/api/service/storage/streaming/dsr_storage.py +1 -5
  33. fides/api/service/storage/streaming/s3/s3_storage_client.py +78 -40
  34. fides/api/service/storage/streaming/s3/streaming_s3.py +9 -21
  35. fides/api/service/storage/streaming/smart_open_client.py +8 -7
  36. fides/api/service/storage/streaming/smart_open_streaming_storage.py +109 -196
  37. fides/api/service/storage/streaming/storage_client_factory.py +7 -3
  38. fides/api/service/storage/util.py +579 -0
  39. fides/api/task/manual/manual_task_graph_task.py +11 -9
  40. fides/api/util/connection_type.py +3 -0
  41. fides/api/util/saas_util.py +12 -1
  42. fides/api/util/text.py +51 -0
  43. fides/common/api/v1/urn_registry.py +3 -0
  44. fides/service/privacy_request/privacy_request_service.py +83 -0
  45. fides/ui-build/static/admin/404.html +1 -1
  46. fides/ui-build/static/admin/_next/static/Pc_eOxj5LbY3XOShbrjSX/_buildManifest.js +1 -0
  47. fides/ui-build/static/admin/_next/static/chunks/1099-79646e64f26d62fa.js +1 -0
  48. fides/ui-build/static/admin/_next/static/chunks/{1345-ab756811e19ff4fc.js → 1345-5e1c5b66e25c566e.js} +1 -1
  49. fides/ui-build/static/admin/_next/static/chunks/{1817-fd21f1f5ef0faffa.js → 1817-3d9e110e007853f0.js} +1 -1
  50. fides/ui-build/static/admin/_next/static/chunks/{1975.16126463309143e3.js → 1975.78e719130cfe3fd6.js} +1 -1
  51. fides/ui-build/static/admin/_next/static/chunks/{2921-0e5cc63a82e31830.js → 2921-52328140bc420d0f.js} +1 -1
  52. fides/ui-build/static/admin/_next/static/chunks/{3620-6cceae71bae5b531.js → 3620-31ebb43dba84cbbd.js} +1 -1
  53. fides/ui-build/static/admin/_next/static/chunks/3729-a1ca1608efc11ac4.js +1 -0
  54. fides/ui-build/static/admin/_next/static/chunks/3847-230bf61b053bc706.js +1 -0
  55. fides/ui-build/static/admin/_next/static/chunks/{3855-64541570e2f838fb.js → 3855-ef5194cdb228beb6.js} +1 -1
  56. fides/ui-build/static/admin/_next/static/chunks/{3872-7a18d18a5e287e4e.js → 3872-a91143aa35fa8ef8.js} +1 -1
  57. fides/ui-build/static/admin/_next/static/chunks/{3923-5c87b3d7f1626678.js → 3923-bb2417b8dcade7a4.js} +1 -1
  58. fides/ui-build/static/admin/_next/static/chunks/{401-3902e3e98790d401.js → 401-4af0a912e249d30f.js} +1 -1
  59. fides/ui-build/static/admin/_next/static/chunks/{4121-64ef70ef906bbdd0.js → 4121-c8d5d717e31899e1.js} +1 -1
  60. fides/ui-build/static/admin/_next/static/chunks/4164-355644b916ae0094.js +1 -0
  61. fides/ui-build/static/admin/_next/static/chunks/{4608-70521532195124de.js → 4608-23bbd4c3c4a59f42.js} +1 -1
  62. fides/ui-build/static/admin/_next/static/chunks/4786-0827aae7aceadd22.js +1 -0
  63. fides/ui-build/static/admin/_next/static/chunks/4808-78ca630f2d2503cd.js +1 -0
  64. fides/ui-build/static/admin/_next/static/chunks/{4844-351f99b6644b654e.js → 4844-46324c3d848b8b6a.js} +1 -1
  65. fides/ui-build/static/admin/_next/static/chunks/{5258-c6f96dc740eb5fb1.js → 5258-b0de22a8521686ab.js} +1 -1
  66. fides/ui-build/static/admin/_next/static/chunks/{5487-338800277d36b8d7.js → 5487-8c635883dcaa9c2a.js} +1 -1
  67. fides/ui-build/static/admin/_next/static/chunks/549-38ea1d91ee2addaa.js +1 -0
  68. fides/ui-build/static/admin/_next/static/chunks/{6084-da63f20d9416a982.js → 6084-0096d7de64ef8015.js} +1 -1
  69. fides/ui-build/static/admin/_next/static/chunks/{6853-1d947b75eb07188c.js → 6853-b17673391117c976.js} +1 -1
  70. fides/ui-build/static/admin/_next/static/chunks/{6954-24f9a4f27d67b732.js → 6954-9d46e2276c461c26.js} +1 -1
  71. fides/ui-build/static/admin/_next/static/chunks/{7476-a0dd03bfccf60d0c.js → 7476-d1b0af9ade392e5b.js} +1 -1
  72. fides/ui-build/static/admin/_next/static/chunks/{7630-9fbe06cfb98266fe.js → 7630-da0a7ce4e3a0d62c.js} +1 -1
  73. fides/ui-build/static/admin/_next/static/chunks/{787-3dd31844cf7fec55.js → 787-3499983fa346b380.js} +1 -1
  74. fides/ui-build/static/admin/_next/static/chunks/{79-dcd20e8b09501c17.js → 79-f197fc4db8d530e5.js} +1 -1
  75. fides/ui-build/static/admin/_next/static/chunks/{796-8773e04b64ce2260.js → 796-db1e30119ea973c7.js} +1 -1
  76. fides/ui-build/static/admin/_next/static/chunks/8002-971e29181f72edd1.js +1 -0
  77. fides/ui-build/static/admin/_next/static/chunks/{9046-57eab238570b8bf4.js → 9046-712156d461165f56.js} +1 -1
  78. fides/ui-build/static/admin/_next/static/chunks/{9676.bf0a8a6ff6dfd2af.js → 9676.9fd9552ef744c717.js} +1 -1
  79. fides/ui-build/static/admin/_next/static/chunks/{9826-756c958aecab59a2.js → 9826-b0b3d3cfb13bfbc1.js} +1 -1
  80. fides/ui-build/static/admin/_next/static/chunks/{9951-cdf73904a3adb27b.js → 9951-a88367a129b724ba.js} +1 -1
  81. fides/ui-build/static/admin/_next/static/chunks/pages/{404-dd625a559ada46ca.js → 404-471a6b18e712f050.js} +1 -1
  82. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-b6b09b2878b77b21.js → _app-ef8e1c986bc5b795.js} +12 -12
  83. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-92cf5e313be1f9e2.js → manual-9dc7e70ab5b05723.js} +1 -1
  84. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-d6c525ee731a2993.js → multiple-4b79a1652297ed9a.js} +1 -1
  85. fides/ui-build/static/admin/_next/static/chunks/pages/{add-systems-5664a3ea796e5ffb.js → add-systems-1632a59203fe8eab.js} +1 -1
  86. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-78f13de90111fd80.js → add-vendors-1ca9df7ca91bd101.js} +1 -1
  87. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-0fc678f3d6d2fcec.js → configure-07bdbc9ae4137db4.js} +1 -1
  88. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-126db59dc25ca326.js → [id]-f80cf2d3966816fd.js} +1 -1
  89. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-289605267d6cce7e.js → privacy-experience-2795cd4115a77c94.js} +1 -1
  90. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-e9fd9b28ac9705af.js → [id]-e02921dc82dccbb1.js} +1 -1
  91. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-28c003b6043bd16c.js → new-98f9e4ba3610628a.js} +1 -1
  92. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-c643eff04525298e.js → privacy-notices-17ed82777810d1c6.js} +1 -1
  93. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-3ef5d01779a26455.js → properties-226efa1dcd41437f.js} +1 -1
  94. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-28b192e2c074b0f3.js +1 -0
  95. fides/ui-build/static/admin/_next/static/chunks/pages/{consent-8d4be9e7ec7d2a35.js → consent-09610b10923d9268.js} +1 -1
  96. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-f27ec4578c674181.js → [resourceUrn]-da1a48336daff6f8.js} +1 -1
  97. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-27b6c255bd9e73b6.js → [projectUrn]-d8e776f1e64e4ba8.js} +1 -1
  98. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{projects-0f66dac32040519c.js → projects-75b9629b0d9cdf96.js} +1 -1
  99. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-3b938562df81c4b0.js → [resourceUrn]-470da05db63767cd.js} +1 -1
  100. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-6984c033b8fe3a13.js +1 -0
  101. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-2f0a33ef9ba1f1da.js +1 -0
  102. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-e9d4f25b20ff6781.js +1 -0
  103. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-9c428d3ef0985915.js +1 -0
  104. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{activity-21c141279e66237a.js → activity-b6ae7adb8ef0b525.js} +1 -1
  105. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-3bc6a207693fd175.js → [resourceUrn]-c3a97e6721ca0abe.js} +1 -1
  106. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-da16e73df395ad1d.js → detection-a0a7de552ef71f5b.js} +1 -1
  107. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-04b242632a114405.js → [resourceUrn]-109754fec0755339.js} +1 -1
  108. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-900fe50183a40d72.js → discovery-88654783b06b3b21.js} +1 -1
  109. fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-4f1f7c3a9531a8f4.js → datamap-89136e6800dc9369.js} +1 -1
  110. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/{[...subfieldNames]-343294dcb10d9532.js → [...subfieldNames]-8f58192dcb54883d.js} +1 -1
  111. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/{[collectionName]-1c097a0809fa5b6f.js → [collectionName]-dcb4ab380a77aa1e.js} +1 -1
  112. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{[datasetId]-b47fa2498b534719.js → [datasetId]-6f16d43071fb9c11.js} +1 -1
  113. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{new-a31f881cab25704a.js → new-97f06e21580f1f6a.js} +1 -1
  114. fides/ui-build/static/admin/_next/static/chunks/pages/{dataset-858c59c9e67e318d.js → dataset-674bb3940f088ecc.js} +1 -1
  115. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-16c28d272225afb6.js → [id]-6f77d8647fca71e0.js} +1 -1
  116. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-821dd1269834cfa2.js +1 -0
  117. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-23e4caf79faa8106.js +1 -0
  118. fides/ui-build/static/admin/_next/static/chunks/pages/{index-fec557d99211f577.js → index-23eb64eed81dcb69.js} +1 -1
  119. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-3a4cd3fe9094fba3.js +1 -0
  120. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-57e618d7b16ac69a.js +1 -0
  121. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-4a08ca7762a19700.js → [id]-c9a323eb6a929476.js} +1 -1
  122. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-343a965dcdb3d11e.js → add-template-b9bb09e46921a590.js} +1 -1
  123. fides/ui-build/static/admin/_next/static/chunks/pages/{messaging-3ade4c54b1c8a11e.js → messaging-82c631a12b5a008c.js} +1 -1
  124. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{ant-components-9103bfb854f71410.js → ant-components-bc0e2adf6e0d3ac7.js} +1 -1
  125. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{AntForm-3b97029bd4d3c3ea.js → AntForm-86ffcc1ad3fa912e.js} +1 -1
  126. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikAntFormItem-9d9beb8f0d8a278c.js → FormikAntFormItem-ec04f595465bdf69.js} +1 -1
  127. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikControlled-84a4d8fc60f839ed.js → FormikControlled-41d309754ff0c1de.js} +1 -1
  128. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikField-1fccf542ab2e33bf.js → FormikField-cab1f78cec7808f9.js} +1 -1
  129. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{forms-aa75263ae1ba67bb.js → forms-eb6058221403b156.js} +1 -1
  130. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{table-migration-db334a1cbb102255.js → table-migration-38360083348c3d6c.js} +1 -1
  131. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{[id]-11c1e4545c8f528c.js → [id]-0d0bb9eb004a3336.js} +1 -1
  132. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{messaging-192a986f61c23268.js → messaging-f9320a58f489f5b7.js} +1 -1
  133. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{storage-9216ac993d71387e.js → storage-d0cfa8aeddd43a40.js} +1 -1
  134. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-e55ec84d5380401d.js → configure-72ca94ec5ed85733.js} +1 -1
  135. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-5a5edc8a4aa7c30a.js +1 -0
  136. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-a74b51b704b80cb2.js → [id]-5ec775c4904fdbfe.js} +1 -1
  137. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-8d23f0c55ff6510a.js → add-property-a6812c0916f2949e.js} +1 -1
  138. fides/ui-build/static/admin/_next/static/chunks/pages/{properties-77acceac4f99e7af.js → properties-da734840e4f9d04b.js} +1 -1
  139. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-6903f42a0412bfa6.js +1 -0
  140. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/{alpha-6aad3f563ed03b3f.js → alpha-3e72e9f91991c119.js} +1 -1
  141. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{about-c1b8f3606d160bb1.js → about-6aab092f4871cecb.js} +1 -1
  142. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/{[purpose_id]-d9f7f78810d58d08.js → [purpose_id]-9495e2eb506606c7.js} +1 -1
  143. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{consent-ee2c7dde99b1dafb.js → consent-be47008304106395.js} +1 -1
  144. fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-ae1b57589da7b175.js +1 -0
  145. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-31c270d228e00581.js → domain-records-23a6d7a921150188.js} +1 -1
  146. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domains-996b3f250dd3ea1f.js → domains-2a9e8859ab4d9de6.js} +1 -1
  147. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-ee94981326ddcbf4.js → email-templates-4f9f0fdf9925ae90.js} +1 -1
  148. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-0b831c58966782b8.js → locations-46f7af35cee4a8bb.js} +1 -1
  149. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-94271ba4a224a353.js → organization-a596a96cb8d0aa8e.js} +1 -1
  150. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-41b8136e50320fd3.js → regulations-6ed5fc2410e00857.js} +1 -1
  151. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-52b45569cbc82e60.js → test-datasets-86811e3cda277e77.js} +1 -1
  152. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-36d74e93e54aabaf.js → [id]-5a43f108d8047d5b.js} +1 -1
  153. fides/ui-build/static/admin/_next/static/chunks/pages/{systems-24dfc8e2279ced2e.js → systems-045a841e22e85ea8.js} +1 -1
  154. fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-d9675cf5e6083b27.js → taxonomy-1b3f2d4bcb0e164d.js} +1 -1
  155. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-866826d7959df487.js → [id]-05d61c80a556b2d5.js} +1 -1
  156. fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-e63b61a8f99ccd57.js → user-management-2cab41659f1ee7da.js} +1 -1
  157. fides/ui-build/static/admin/_next/static/chunks/{webpack-6d0a487039bcf30c.js → webpack-678e89d68dbcd94f.js} +1 -1
  158. fides/ui-build/static/admin/_next/static/css/650df9c348000a26.css +1 -0
  159. fides/ui-build/static/admin/_next/static/css/{dbcf63488933a4d5.css → 98fab0b3e6aa43ed.css} +1 -1
  160. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  161. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  162. fides/ui-build/static/admin/add-systems.html +1 -1
  163. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  164. fides/ui-build/static/admin/consent/configure.html +1 -1
  165. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  166. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  167. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  168. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  169. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  170. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  171. fides/ui-build/static/admin/consent/properties.html +1 -1
  172. fides/ui-build/static/admin/consent/reporting.html +1 -1
  173. fides/ui-build/static/admin/consent.html +1 -1
  174. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  175. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  176. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  177. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  178. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  179. fides/ui-build/static/admin/data-catalog.html +1 -1
  180. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  181. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  182. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  183. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  184. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  185. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  186. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  187. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  188. fides/ui-build/static/admin/datamap.html +1 -1
  189. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  190. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  191. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  192. fides/ui-build/static/admin/dataset/new.html +1 -1
  193. fides/ui-build/static/admin/dataset.html +1 -1
  194. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  195. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  196. fides/ui-build/static/admin/datastore-connection.html +1 -1
  197. fides/ui-build/static/admin/index.html +1 -1
  198. fides/ui-build/static/admin/integrations/[id].html +1 -1
  199. fides/ui-build/static/admin/integrations.html +1 -1
  200. fides/ui-build/static/admin/lib/fides-ext-gpp.js +1 -1
  201. fides/ui-build/static/admin/lib/fides-headless.js +1 -1
  202. fides/ui-build/static/admin/lib/fides-preview.js +1 -1
  203. fides/ui-build/static/admin/lib/fides-tcf.js +2 -2
  204. fides/ui-build/static/admin/lib/fides.js +2 -2
  205. fides/ui-build/static/admin/login/[provider].html +1 -1
  206. fides/ui-build/static/admin/login.html +1 -1
  207. fides/ui-build/static/admin/messaging/[id].html +1 -1
  208. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  209. fides/ui-build/static/admin/messaging.html +1 -1
  210. fides/ui-build/static/admin/poc/ant-components.html +1 -1
  211. fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
  212. fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
  213. fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
  214. fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
  215. fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
  216. fides/ui-build/static/admin/poc/forms.html +1 -1
  217. fides/ui-build/static/admin/poc/table-migration.html +1 -1
  218. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  219. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  220. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  221. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  222. fides/ui-build/static/admin/privacy-requests.html +1 -1
  223. fides/ui-build/static/admin/properties/[id].html +1 -1
  224. fides/ui-build/static/admin/properties/add-property.html +1 -1
  225. fides/ui-build/static/admin/properties.html +1 -1
  226. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  227. fides/ui-build/static/admin/settings/about/alpha.html +1 -1
  228. fides/ui-build/static/admin/settings/about.html +1 -1
  229. fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
  230. fides/ui-build/static/admin/settings/consent.html +1 -1
  231. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  232. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  233. fides/ui-build/static/admin/settings/domains.html +1 -1
  234. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  235. fides/ui-build/static/admin/settings/locations.html +1 -1
  236. fides/ui-build/static/admin/settings/organization.html +1 -1
  237. fides/ui-build/static/admin/settings/regulations.html +1 -1
  238. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  239. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  240. fides/ui-build/static/admin/systems.html +1 -1
  241. fides/ui-build/static/admin/taxonomy.html +1 -1
  242. fides/ui-build/static/admin/user-management/new.html +1 -1
  243. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  244. fides/ui-build/static/admin/user-management.html +1 -1
  245. fides/ui-build/static/admin/_next/static/_BLI2ArqQzY5XnXbrcxa2/_buildManifest.js +0 -1
  246. fides/ui-build/static/admin/_next/static/chunks/1099-7b2085a3931da9e4.js +0 -1
  247. fides/ui-build/static/admin/_next/static/chunks/1138-0d846ffef62c580f.js +0 -1
  248. fides/ui-build/static/admin/_next/static/chunks/3729-7d2d52400f1f7413.js +0 -1
  249. fides/ui-build/static/admin/_next/static/chunks/4786-53ef1662f2d0d98c.js +0 -1
  250. fides/ui-build/static/admin/_next/static/chunks/4808-8713433c84a62efe.js +0 -1
  251. fides/ui-build/static/admin/_next/static/chunks/549-e6453a3526023e85.js +0 -1
  252. fides/ui-build/static/admin/_next/static/chunks/602-80d113e801d7407d.js +0 -1
  253. fides/ui-build/static/admin/_next/static/chunks/8002-dcd02da6e5649a1c.js +0 -1
  254. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-baa4a2f8f08ac224.js +0 -1
  255. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-ebf5e7fa4e2ffb49.js +0 -1
  256. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-b27c660039d951c9.js +0 -1
  257. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-8ce5d24af470888e.js +0 -1
  258. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-8e35e33928abbcdc.js +0 -1
  259. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-68f502d8b0b5792c.js +0 -1
  260. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-1eb9acb17b133fd1.js +0 -1
  261. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-e613543818d6cbd2.js +0 -1
  262. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-8069f7c33695fd45.js +0 -1
  263. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-48f447b31c786b80.js +0 -1
  264. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-e60d398e255f4e00.js +0 -1
  265. fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-a4dad8ca9de2d07b.js +0 -1
  266. fides/ui-build/static/admin/_next/static/css/92441453b27e9c34.css +0 -1
  267. {ethyca_fides-2.68.1b3.dist-info → ethyca_fides-2.69.0.dist-info}/WHEEL +0 -0
  268. {ethyca_fides-2.68.1b3.dist-info → ethyca_fides-2.69.0.dist-info}/entry_points.txt +0 -0
  269. {ethyca_fides-2.68.1b3.dist-info → ethyca_fides-2.69.0.dist-info}/licenses/LICENSE +0 -0
  270. {ethyca_fides-2.68.1b3.dist-info → ethyca_fides-2.69.0.dist-info}/top_level.txt +0 -0
  271. /fides/ui-build/static/admin/_next/static/{_BLI2ArqQzY5XnXbrcxa2 → Pc_eOxj5LbY3XOShbrjSX}/_ssgManifest.js +0 -0
@@ -35,7 +35,9 @@
35
35
  {% endif %}
36
36
 
37
37
  {% if _is_attachment_block %}
38
- <p class="expiration-notice">Note: All download links will expire in 7 days.</p>
38
+ {% if not enable_streaming %}
39
+ <p class="expiration-notice">Note: All download links will expire in {{ download_link_ttl_days }} days.</p>
40
+ {% endif %}
39
41
  <div class="table table-hover">
40
42
  <div class="table-row">
41
43
  <div class="table-cell" style="text-align: left;">File Name</div>
@@ -27,4 +27,4 @@
27
27
  </div>
28
28
  </div>
29
29
  </body>
30
- </html>
30
+ </html>
@@ -41,6 +41,9 @@ from fides.api.models.privacy_request import (
41
41
  ProvidedIdentityType,
42
42
  can_run_checkpoint,
43
43
  )
44
+ from fides.api.models.privacy_request.webhook import (
45
+ generate_privacy_request_download_token,
46
+ )
44
47
  from fides.api.schemas.base_class import FidesSchema
45
48
  from fides.api.schemas.messaging.messaging import (
46
49
  AccessRequestCompleteBodyParams,
@@ -49,6 +52,7 @@ from fides.api.schemas.messaging.messaging import (
49
52
  from fides.api.schemas.policy import ActionType, CurrentStep
50
53
  from fides.api.schemas.privacy_request import PrivacyRequestStatus
51
54
  from fides.api.schemas.redis_cache import Identity
55
+ from fides.api.schemas.storage.storage import StorageType
52
56
  from fides.api.service.connectors import FidesConnector, get_connector
53
57
  from fides.api.service.connectors.consent_email_connector import (
54
58
  CONSENT_EMAIL_CONNECTOR_TYPES,
@@ -82,6 +86,7 @@ from fides.api.util.logger import Pii, _log_exception, _log_warning
82
86
  from fides.api.util.logger_context_utils import LoggerContextKeys, log_context
83
87
  from fides.api.util.memory_watchdog import memory_limiter
84
88
  from fides.common.api.v1.urn_registry import (
89
+ PRIVACY_CENTER_DSR_PACKAGE,
85
90
  PRIVACY_REQUEST_TRANSFER_TO_PARENT,
86
91
  V1_URL_PREFIX,
87
92
  )
@@ -307,8 +312,14 @@ def upload_and_save_access_results( # pylint: disable=R0912
307
312
  loaded_attachments = [
308
313
  attachment
309
314
  for attachment in privacy_request.attachments
310
- if AttachmentReferenceType.access_manual_webhook
311
- not in [ref.reference_type for ref in attachment.references]
315
+ if not any(
316
+ ref.reference_type
317
+ in [
318
+ AttachmentReferenceType.access_manual_webhook,
319
+ AttachmentReferenceType.manual_task_submission,
320
+ ]
321
+ for ref in attachment.references
322
+ )
312
323
  ]
313
324
  attachments = get_attachments_content(loaded_attachments)
314
325
  # Process attachments once for both upload and storage
@@ -609,6 +620,9 @@ def run_privacy_request(
609
620
  # The access, consent, and erasure runners for DSR 3.0 throw this exception after its
610
621
  # Request Tasks have been built. The Privacy Request will be requeued from
611
622
  # the appropriate checkpoint when all the Request Tasks have run.
623
+ logger.info(
624
+ "Privacy Request exited awaiting sub task processing (Request Tasks)"
625
+ )
612
626
  return
613
627
 
614
628
  except ValidationError as exc:
@@ -740,14 +754,17 @@ def run_privacy_request(
740
754
  else MessagingActionType.PRIVACY_REQUEST_COMPLETE_DELETION
741
755
  )
742
756
 
743
- if message_send_enabled(
757
+ message_send_result = message_send_enabled(
744
758
  session,
745
759
  privacy_request.property_id,
746
760
  action_type,
747
761
  legacy_request_completion_enabled,
748
- ) and not policy.get_rules_for_action(
762
+ )
763
+ has_consent_rules = policy.get_rules_for_action(
749
764
  action_type=ActionType.consent
750
- ):
765
+ )
766
+
767
+ if message_send_result and not has_consent_rules:
751
768
  if not access_result_urls:
752
769
  # For DSR 3.0, if the request had both access and erasure rules, this needs to be fetched
753
770
  # from the database because the Privacy Request would have exited
@@ -763,6 +780,7 @@ def run_privacy_request(
763
780
  access_result_urls,
764
781
  identity_data,
765
782
  privacy_request.property_id,
783
+ privacy_request.id,
766
784
  )
767
785
  except (
768
786
  IdentityNotFoundException,
@@ -780,6 +798,7 @@ def initiate_privacy_request_completion_email(
780
798
  access_result_urls: list[str],
781
799
  identity_data: dict[str, Any],
782
800
  property_id: Optional[str],
801
+ privacy_request_id: str,
783
802
  ) -> None:
784
803
  """
785
804
  :param session: SQLAlchemy Session
@@ -787,6 +806,7 @@ def initiate_privacy_request_completion_email(
787
806
  :param access_result_urls: list of urls generated by access request upload
788
807
  :param identity_data: Dict of identity data
789
808
  :param property_id: Property id associated with the privacy request
809
+ :param privacy_request_id: ID of the privacy request for generating DSR package links
790
810
  """
791
811
  config_proxy = ConfigProxy(session)
792
812
  if not (
@@ -801,6 +821,32 @@ def initiate_privacy_request_completion_email(
801
821
  phone_number=identity_data.get(ProvidedIdentityType.phone_number.value),
802
822
  )
803
823
  if policy.get_rules_for_action(action_type=ActionType.access):
824
+ # Check if any rule has enable_access_package_redirect=True and enable_streaming=True in storage config
825
+ # This can be extended to other storage types and non streaming access results in the future
826
+ use_dsr_package_links = False
827
+ for rule in policy.get_rules_for_action(action_type=ActionType.access):
828
+ storage_destination = rule.get_storage_destination(session)
829
+ if (
830
+ storage_destination.type == StorageType.s3
831
+ and storage_destination.details.get("enable_access_package_redirect")
832
+ and storage_destination.details.get("enable_streaming")
833
+ ):
834
+ use_dsr_package_links = True
835
+ break
836
+
837
+ # Generate appropriate URLs based on streaming configuration
838
+ if use_dsr_package_links and config_proxy.privacy_center.url:
839
+ # Use DSR package links instead of direct storage URLs
840
+ # Generate the download token for security
841
+ download_token = generate_privacy_request_download_token(privacy_request_id)
842
+
843
+ # Generate DSR package URLs for the messaging template system
844
+ dsr_package_url = f"{config_proxy.privacy_center.url}/api{PRIVACY_CENTER_DSR_PACKAGE.format(privacy_request_id=privacy_request_id)}?token={download_token}"
845
+ download_links = [dsr_package_url]
846
+ else:
847
+ # Use original direct storage URLs
848
+ download_links = access_result_urls
849
+
804
850
  # synchronous for now since failure to send complete emails is fatal to request
805
851
  dispatch_message(
806
852
  db=session,
@@ -808,7 +854,7 @@ def initiate_privacy_request_completion_email(
808
854
  to_identity=to_identity,
809
855
  service_type=config_proxy.notifications.notification_service_type,
810
856
  message_body_params=AccessRequestCompleteBodyParams(
811
- download_links=access_result_urls,
857
+ download_links=download_links,
812
858
  subject_request_download_time_in_days=CONFIG.security.subject_request_download_link_ttl_seconds
813
859
  / 86400,
814
860
  ),
@@ -540,6 +540,7 @@ def _get_request_task_ids_in_progress(
540
540
 
541
541
 
542
542
  # pylint: disable=too-many-branches
543
+ # pylint: disable=too-many-statements
543
544
  @celery_app.task(base=DatabaseTask, bind=True)
544
545
  def requeue_interrupted_tasks(self: DatabaseTask) -> None:
545
546
  """
@@ -660,8 +661,24 @@ def requeue_interrupted_tasks(self: DatabaseTask) -> None:
660
661
  break
661
662
 
662
663
  # If the task ID is not cached, we can't check if it's running
663
- # This means the subtask is stuck - cancel the entire privacy request
664
+ # This means the subtask is stuck - but we need to handle this differently
665
+ # based on the privacy request status
664
666
  if not subtask_id:
667
+ if (
668
+ privacy_request.status
669
+ == PrivacyRequestStatus.requires_input
670
+ ):
671
+ # For requires_input status, don't automatically error the request
672
+ # as it's intentionally waiting for user input
673
+ logger.warning(
674
+ f"No task ID found for request task {request_task_id} "
675
+ f"(privacy request {privacy_request.id}) in requires_input status - "
676
+ f"keeping request in current status as it may be waiting for manual input"
677
+ )
678
+ should_requeue = False
679
+ break
680
+
681
+ # For other statuses, cancel the entire privacy request
665
682
  _cancel_interrupted_tasks_and_error_privacy_request(
666
683
  db,
667
684
  privacy_request,
@@ -51,13 +51,7 @@ def upload(
51
51
  config.secrets is not None,
52
52
  )
53
53
 
54
- if config.secrets:
55
- logger.debug("Storage config secrets type: {}", type(config.secrets))
56
- if isinstance(config.secrets, dict):
57
- logger.debug("Storage config secrets keys: {}", list(config.secrets.keys()))
58
- else:
59
- logger.debug("Storage config secrets is not a dict: {}", config.secrets)
60
- else:
54
+ if not config.secrets:
61
55
  logger.warning("Storage config has no secrets!")
62
56
 
63
57
  uploader: Any = _get_uploader_from_config_type(config.type) # type: ignore
@@ -130,19 +124,6 @@ def _s3_uploader(
130
124
  config.secrets is not None,
131
125
  )
132
126
 
133
- if config.secrets:
134
- logger.debug(
135
- "Config secrets keys: {}",
136
- (
137
- list(config.secrets.keys())
138
- if isinstance(config.secrets, dict)
139
- else "Not a dict"
140
- ),
141
- )
142
- logger.debug("Config secrets type: {}", type(config.secrets))
143
- else:
144
- logger.warning("Config secrets is None or empty!")
145
-
146
127
  enable_streaming = config.details.get(StorageDetails.ENABLE_STREAMING.value, False)
147
128
  file_key: str = _construct_file_key(privacy_request.id, config, enable_streaming)
148
129
 
@@ -154,7 +135,6 @@ def _s3_uploader(
154
135
  file_key = f"{privacy_request.id}.zip"
155
136
  # Use streaming upload for better memory efficiency
156
137
  logger.debug("Using streaming S3 upload for {}", file_key)
157
- logger.debug("Calling upload_to_s3_streaming with secrets: {}", config.secrets)
158
138
  return upload_to_s3_streaming(
159
139
  config.secrets, # type: ignore
160
140
  data,
@@ -17,7 +17,6 @@ def stream_dsr_buffer_to_storage(
17
17
  bucket_name: str,
18
18
  file_key: str,
19
19
  dsr_buffer: BytesIO,
20
- content_type: str = "application/zip",
21
20
  ) -> None:
22
21
  """Stream DSR buffer to storage using smart-open streaming.
23
22
 
@@ -29,15 +28,12 @@ def stream_dsr_buffer_to_storage(
29
28
  bucket_name: Storage bucket name
30
29
  file_key: File key in storage
31
30
  dsr_buffer: Pre-generated DSR report buffer (BytesIO)
32
- content_type: MIME type for the uploaded file (defaults to application/zip)
33
31
  """
34
32
  # Get the content from the buffer
35
33
  content = dsr_buffer.getvalue()
36
34
  try:
37
35
  # Use smart-open's streaming upload for efficient memory usage
38
- with storage_client.stream_upload(
39
- bucket_name, file_key, content_type=content_type
40
- ) as upload_stream:
36
+ with storage_client.stream_upload(bucket_name, file_key) as upload_stream:
41
37
  upload_stream.write(content)
42
38
 
43
39
  except Exception as e:
@@ -7,7 +7,7 @@ from typing import Any, Optional
7
7
  from fideslang.validation import AnyHttpUrlString
8
8
  from loguru import logger
9
9
 
10
- from fides.api.schemas.storage.storage import AWSAuthMethod, StorageSecrets
10
+ from fides.api.schemas.storage.storage import AWSAuthMethod
11
11
  from fides.api.service.storage.s3 import create_presigned_url_for_s3
12
12
  from fides.api.service.storage.streaming.base_storage_client import BaseStorageClient
13
13
  from fides.api.util.aws_util import get_s3_client
@@ -20,17 +20,19 @@ class S3StorageClient(BaseStorageClient):
20
20
  generation for the smart-open storage client.
21
21
  """
22
22
 
23
- def __init__(self, storage_secrets: dict[StorageSecrets, Any]):
23
+ def __init__(self, auth_method: str, storage_secrets: dict[str, Any]):
24
24
  """Initialize the storage client with secrets.
25
25
 
26
26
  Args:
27
- storage_secrets: Provider-specific storage credentials and configuration using StorageSecrets enum keys
27
+ storage_secrets: Provider-specific storage credentials and configuration using string keys
28
+ (e.g., "aws_access_key_id", "region_name") from format_secrets()
28
29
  """
29
30
  super().__init__(storage_secrets)
30
- self.storage_secrets: dict[StorageSecrets, Any] = storage_secrets
31
+ self.storage_secrets: dict[str, Any] = storage_secrets
32
+ self.auth_method = auth_method
31
33
 
32
34
  def build_uri(self, bucket: str, key: str) -> str:
33
- """Build the S3 URI for the storage location.
35
+ """Build S3 URI for the given bucket and key.
34
36
 
35
37
  Args:
36
38
  bucket: S3 bucket name
@@ -45,26 +47,75 @@ class S3StorageClient(BaseStorageClient):
45
47
 
46
48
  def get_transport_params(self) -> dict[str, Any]:
47
49
  """Get S3-specific transport parameters for smart-open.
50
+ Type annotation: get_s3_client returns a boto3 S3 client object, not a Session
51
+ This is what smart-open expects for the "client" transport parameter
48
52
 
49
53
  Returns:
50
54
  Dictionary of S3 transport parameters for smart-open
51
55
  """
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
- ]
56
+ params: dict[str, Any] = {}
57
+
58
+ # Create S3 client for smart-open
59
+ try:
60
+ # Determine auth method based on available credentials
61
+ if self.auth_method == AWSAuthMethod.AUTOMATIC.value:
62
+
63
+ # For automatic authentication, check if region is available
64
+ if not self.storage_secrets.get("region_name", None):
65
+ logger.warning(
66
+ "No region specified in storage secrets for automatic authentication"
67
+ "This may cause credential issues - consider setting a default region"
68
+ )
69
+
70
+ # Extract assume_role_arn if present
71
+ assume_role_arn = None
72
+ if (
73
+ "assume_role_arn" in self.storage_secrets
74
+ and self.storage_secrets["assume_role_arn"]
75
+ ):
76
+ assume_role_arn = self.storage_secrets["assume_role_arn"]
77
+ logger.debug(f"Using assume role ARN: {assume_role_arn}")
78
+
79
+ # Create S3 client using existing utility
80
+ # get_s3_client returns a boto3 S3 client, not a Session
81
+ s3_client: Any = None
82
+ try:
83
+ s3_client = get_s3_client(
84
+ self.auth_method, self.storage_secrets, assume_role_arn # type: ignore
85
+ )
86
+ logger.debug("Successfully created S3 client")
87
+ except Exception as e:
88
+ # For automatic authentication, try to provide more helpful error messages
89
+ if self.auth_method == AWSAuthMethod.AUTOMATIC.value:
90
+ logger.error(
91
+ f"Failed to create S3 client with automatic authentication: {e}. "
92
+ "This usually means AWS credentials are not available in the environment"
93
+ "Please ensure AWS credentials are configured via environment variables, IAM roles, or AWS profiles"
94
+ )
95
+ raise ValueError(
96
+ f"Automatic AWS authentication failed: {e}. Please check your AWS credential configuration."
97
+ )
98
+ raise
99
+
100
+ params["client"] = s3_client
101
+
102
+ except Exception as e:
103
+ logger.error(f"Failed to create S3 client for smart-open: {e}")
104
+ raise
105
+
106
+ # Include credentials at top level for compatibility
107
+ # Note: When using an S3 client, these credential parameters are not needed
108
+ # and will be ignored by smart-open, causing warnings
109
+ # Only include them if no S3 client is provided (fallback scenario)
110
+ if not params.get("client"):
111
+ for key, transport_key in [
112
+ ("aws_access_key_id", "access_key"),
113
+ ("aws_secret_access_key", "secret_key"),
114
+ ("region_name", "region"),
115
+ ("assume_role_arn", "assume_role_arn"),
116
+ ]:
117
+ if key in self.storage_secrets and self.storage_secrets[key]:
118
+ params[transport_key] = self.storage_secrets[key]
68
119
 
69
120
  return params
70
121
 
@@ -85,28 +136,15 @@ class S3StorageClient(BaseStorageClient):
85
136
  Exception: If presigned URL generation fails
86
137
  """
87
138
  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
139
  # Extract assume_role_arn if present for role assumption
105
140
  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]
141
+ if "assume_role_arn" in self.storage_secrets:
142
+ assume_role_arn = self.storage_secrets["assume_role_arn"]
108
143
 
109
- s3_client = get_s3_client(auth_method, s3_secrets, assume_role_arn)
144
+ # get_s3_client returns a boto3 S3 client, not a Session
145
+ s3_client: Any = get_s3_client(
146
+ self.auth_method, self.storage_secrets, assume_role_arn # type: ignore
147
+ )
110
148
  return create_presigned_url_for_s3(s3_client, bucket, key, ttl_seconds)
111
149
  except Exception as e:
112
150
  logger.error(f"Failed to generate S3 presigned URL: {e}")
@@ -54,7 +54,8 @@ def upload_to_s3_streaming(
54
54
  return response
55
55
 
56
56
  try:
57
- storage_client = SmartOpenStorageClient("s3", formatted_secrets)
57
+ logger.debug("Creating SmartOpenStorageClient with formatted secrets")
58
+ storage_client = SmartOpenStorageClient("s3", auth_method, formatted_secrets)
58
59
 
59
60
  # Create upload config for the streaming interface
60
61
  upload_config = StorageUploadConfig(
@@ -92,6 +93,10 @@ def _process_storage_secrets_input(
92
93
  """Process input and convert to string-keyed dictionary."""
93
94
  final_secrets: dict[str, Any] = {}
94
95
 
96
+ logger.debug(
97
+ f"Processing storage secrets input of type: {type(storage_secrets).__name__}"
98
+ )
99
+
95
100
  if isinstance(storage_secrets, StorageSecretsS3):
96
101
  # Convert StorageSecretsS3 model directly to string keys
97
102
  for key, value in storage_secrets.model_dump().items():
@@ -133,6 +138,7 @@ def _validate_aws_credentials(final_secrets: dict[str, Any]) -> None:
133
138
  else:
134
139
  # AUTOMATIC authentication - check if region is provided
135
140
  has_region = "region_name" in final_secrets and final_secrets["region_name"]
141
+
136
142
  if not has_region:
137
143
  raise ValueError(
138
144
  "Missing required region_name for AUTOMATIC authentication. "
@@ -140,13 +146,6 @@ def _validate_aws_credentials(final_secrets: dict[str, Any]) -> None:
140
146
  )
141
147
 
142
148
 
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
149
  def format_secrets(
151
150
  storage_secrets: Union[StorageSecretsS3, dict[StorageSecrets, Any]] # type: ignore[misc]
152
151
  ) -> dict[str, Any]:
@@ -156,8 +155,8 @@ def format_secrets(
156
155
  This function handles multiple credential formats and processes them through several stages:
157
156
  1. Input processing: Accepts either StorageSecretsS3 models (from API) or raw dicts (from database)
158
157
  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)
158
+ 3. Default setting: Sets default region if missing (before validation for better automatic auth support)
159
+ 4. Validation: Ensures required AWS credentials are present based on auth method
161
160
  5. Return: Returns string-keyed dict ready for S3StorageClient
162
161
 
163
162
  Input formats:
@@ -179,18 +178,7 @@ def format_secrets(
179
178
  Raises:
180
179
  ValueError: If required AWS credentials are missing for the chosen auth method
181
180
  """
182
- logger.debug("format_secrets called with type: {}", type(storage_secrets).__name__)
183
-
184
- # Stage 1: Process input and create final format directly
185
181
  final_secrets = _process_storage_secrets_input(storage_secrets)
186
-
187
- # Stage 2: Validate required credentials BEFORE setting defaults
188
182
  _validate_aws_credentials(final_secrets)
189
183
 
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
184
  return final_secrets
@@ -29,7 +29,12 @@ class SmartOpenStorageClient:
29
29
 
30
30
  min_part_size: int = MIN_PART_SIZE
31
31
 
32
- def __init__(self, storage_type: str, storage_secrets: Any):
32
+ def __init__(
33
+ self,
34
+ storage_type: str,
35
+ auth_method: Optional[str],
36
+ storage_secrets: Any,
37
+ ):
33
38
  """Initialize the smart-open storage client.
34
39
 
35
40
  Args:
@@ -38,9 +43,10 @@ class SmartOpenStorageClient:
38
43
  Will be passed to the specific storage client implementation.
39
44
  """
40
45
  self.storage_type = StorageClientFactory._normalize_storage_type(storage_type)
46
+ self.auth_method = auth_method
41
47
  self.storage_secrets = storage_secrets
42
48
  self._provider_client = StorageClientFactory.create_client(
43
- storage_type, storage_secrets
49
+ storage_type, auth_method, storage_secrets
44
50
  )
45
51
 
46
52
  def _build_uri(self, bucket: str, key: str) -> str:
@@ -216,7 +222,6 @@ class SmartOpenStorageClient:
216
222
  self,
217
223
  bucket: str,
218
224
  key: str,
219
- content_type: Optional[str] = None,
220
225
  ) -> Any:
221
226
  """Get a writable stream for uploading data.
222
227
 
@@ -225,7 +230,6 @@ class SmartOpenStorageClient:
225
230
  Args:
226
231
  bucket: Storage bucket/container name
227
232
  key: Object key/path
228
- content_type: MIME type of the object
229
233
 
230
234
  Returns:
231
235
  Writable file-like object
@@ -233,9 +237,6 @@ class SmartOpenStorageClient:
233
237
  uri = self._build_uri(bucket, key)
234
238
  transport_params = self._get_transport_params()
235
239
 
236
- if content_type:
237
- transport_params["content_type"] = content_type
238
-
239
240
  return smart_open.open(uri, "wb", transport_params=transport_params)
240
241
 
241
242
  @retry_cloud_storage_operation(