ethyca-fides 2.64.6b1__py2.py3-none-any.whl → 2.65.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 (235) hide show
  1. {ethyca_fides-2.64.6b1.dist-info → ethyca_fides-2.65.0.dist-info}/METADATA +1 -1
  2. {ethyca_fides-2.64.6b1.dist-info → ethyca_fides-2.65.0.dist-info}/RECORD +222 -217
  3. fides/_version.py +3 -3
  4. fides/api/alembic/migrations/versions/641f6bcd424f_add_user_id_to_manual_task_log.py +28 -0
  5. fides/api/api/v1/endpoints/generic_overrides.py +13 -3
  6. fides/api/email_templates/get_email_template.py +4 -1
  7. fides/api/email_templates/template_names.py +1 -0
  8. fides/api/email_templates/templates/external_user_welcome.html +23 -0
  9. fides/api/models/fides_user_respondent_email_verification.py +3 -3
  10. fides/api/models/manual_task.py +12 -0
  11. fides/api/oauth/utils.py +11 -0
  12. fides/api/request_context.py +76 -0
  13. fides/api/schemas/messaging/messaging.py +14 -0
  14. fides/api/schemas/saas/strategy_configuration.py +6 -0
  15. fides/api/service/connectors/saas_connector.py +43 -1
  16. fides/api/service/execution_context.py +59 -0
  17. fides/api/service/messaging/message_dispatch_service.py +33 -1
  18. fides/api/service/processors/post_processor_strategy/__init__.py +1 -0
  19. fides/api/service/processors/post_processor_strategy/post_processor_strategy.py +11 -1
  20. fides/api/service/processors/post_processor_strategy/post_processor_strategy_extract_for_execution_log.py +73 -0
  21. fides/api/service/processors/post_processor_strategy/post_processor_strategy_factory.py +4 -0
  22. fides/api/service/processors/post_processor_strategy/post_processor_strategy_filter.py +2 -0
  23. fides/api/service/processors/post_processor_strategy/post_processor_strategy_unwrap.py +2 -0
  24. fides/api/task/graph_task.py +38 -18
  25. fides/api/task/manual/manual_task_utils.py +82 -43
  26. fides/ui-build/static/admin/404.html +1 -1
  27. fides/ui-build/static/admin/_next/static/chunks/{1040-d246ed641088a416.js → 1040-94f81c731c29246d.js} +1 -1
  28. fides/ui-build/static/admin/_next/static/chunks/{1817-60f08a3619b9139c.js → 1817-f2f34b8bd569ae1d.js} +1 -1
  29. fides/ui-build/static/admin/_next/static/chunks/{2921-85515257dd94ef4d.js → 2921-c19da1016b81bda3.js} +1 -1
  30. fides/ui-build/static/admin/_next/static/chunks/3450-84ea89e7a0f95470.js +1 -0
  31. fides/ui-build/static/admin/_next/static/chunks/{3855-2d045674fbf72a3c.js → 3855-44e1171660633b6f.js} +1 -1
  32. fides/ui-build/static/admin/_next/static/chunks/{3872-056ddf3ed9d10b51.js → 3872-a7ee651751f5e145.js} +1 -1
  33. fides/ui-build/static/admin/_next/static/chunks/{3923-257df982a95371b5.js → 3923-5a82816119f8f907.js} +1 -1
  34. fides/ui-build/static/admin/_next/static/chunks/3988-046b3a2866b5cb99.js +1 -0
  35. fides/ui-build/static/admin/_next/static/chunks/{401-3f2160e3910d075b.js → 401-7fa53f1e774e02fb.js} +1 -1
  36. fides/ui-build/static/admin/_next/static/chunks/{409-3e2248a63dd60e58.js → 409-03011bbedb4d72f6.js} +1 -1
  37. fides/ui-build/static/admin/_next/static/chunks/4121-536e7e853d0833c0.js +1 -0
  38. fides/ui-build/static/admin/_next/static/chunks/{4230-38c6e446801a8729.js → 4230-864eac33691cd299.js} +1 -1
  39. fides/ui-build/static/admin/_next/static/chunks/{431-13b0ef67d5a3df2f.js → 431-458946a2cae21b5d.js} +1 -1
  40. fides/ui-build/static/admin/_next/static/chunks/{5309-fd8cd5aedd45f7c1.js → 5309-018fe2068151d699.js} +1 -1
  41. fides/ui-build/static/admin/_next/static/chunks/{5574-028ef28c3cf16995.js → 5574-48d7c9a526a3a0fe.js} +1 -1
  42. fides/ui-build/static/admin/_next/static/chunks/{6084-fa1c82d03f6c256a.js → 6084-4a1964e1b20c9eee.js} +1 -1
  43. fides/ui-build/static/admin/_next/static/chunks/6662-f2c51b0c01603952.js +1 -0
  44. fides/ui-build/static/admin/_next/static/chunks/{6853-2644f28976b46c25.js → 6853-19268388843a58f5.js} +1 -1
  45. fides/ui-build/static/admin/_next/static/chunks/{6882-ea071425d25dd2b0.js → 6882-f807b643776c8d47.js} +1 -1
  46. fides/ui-build/static/admin/_next/static/chunks/{6954-bb360fb60aac9440.js → 6954-ec0697d355730f74.js} +1 -1
  47. fides/ui-build/static/admin/_next/static/chunks/{7476-7073ec015f84a3e0.js → 7476-7fc24f19a2cc563a.js} +1 -1
  48. fides/ui-build/static/admin/_next/static/chunks/{7630-302a13c63f9bfb45.js → 7630-e0e04e495732ae8f.js} +1 -1
  49. fides/ui-build/static/admin/_next/static/chunks/{787-b393c03ade9d93dc.js → 787-0c18bf9acef937de.js} +1 -1
  50. fides/ui-build/static/admin/_next/static/chunks/{79-b67ba449b0f2cc9c.js → 79-d4c8900a83eb83bc.js} +1 -1
  51. fides/ui-build/static/admin/_next/static/chunks/{796-b7608f09607288b8.js → 796-a98f370ec9b5cbf9.js} +1 -1
  52. fides/ui-build/static/admin/_next/static/chunks/{9046-ece5efe762b810cb.js → 9046-b3dccae317a7bae5.js} +1 -1
  53. fides/ui-build/static/admin/_next/static/chunks/{9226-c9111590692341b1.js → 9226-a5904e64ab72cb18.js} +1 -1
  54. fides/ui-build/static/admin/_next/static/chunks/{9392.9a948112de74781b.js → 9392.bb5a989efef5b329.js} +1 -1
  55. fides/ui-build/static/admin/_next/static/chunks/{9676.cc515c853b8cf578.js → 9676.549c72c3eb3df912.js} +1 -1
  56. fides/ui-build/static/admin/_next/static/chunks/{9767-277a0229aae7662a.js → 9767-9afc910b855d913a.js} +1 -1
  57. fides/ui-build/static/admin/_next/static/chunks/{9826-82c473dcaf892d00.js → 9826-7b769d4863df242a.js} +1 -1
  58. fides/ui-build/static/admin/_next/static/chunks/{9951-dbd76d7f3a7f1b9a.js → 9951-27d79500acfefdd2.js} +1 -1
  59. fides/ui-build/static/admin/_next/static/chunks/pages/{404-ef01376efb8427e1.js → 404-ac335065bc49f818.js} +1 -1
  60. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-7430e1499432b029.js → _app-ecf5a5601e266a1e.js} +56 -56
  61. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-4057c399f58d331e.js → manual-3964f3039ce3f18c.js} +1 -1
  62. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-2726ca51f0327347.js → multiple-a2ae50c2f0e7608e.js} +1 -1
  63. fides/ui-build/static/admin/_next/static/chunks/pages/{add-systems-a2457d5da25aa854.js → add-systems-4f20f18ec01fd15a.js} +1 -1
  64. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-9fe46ed10a7e7a1a.js → add-vendors-4957c0b6fa498f6e.js} +1 -1
  65. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{configure-095828301f22cdaa.js → configure-3ede98dedea9f621.js} +1 -1
  66. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-de60a5b74f6b20ff.js → [id]-f285b2dca83711ba.js} +1 -1
  67. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-1ee05fd0bc012ec6.js → privacy-experience-efa0f3e3991dc139.js} +1 -1
  68. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-5a2e61c7d88bdda1.js → [id]-21c96b42424c33bc.js} +1 -1
  69. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-1bc69669215fa55c.js → new-e494f14ce371390c.js} +1 -1
  70. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-notices-fa8394d2e1072aba.js → privacy-notices-25cb30b4585622d6.js} +1 -1
  71. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-213c5405e9e4219c.js → properties-78ba4553dd12d0d3.js} +1 -1
  72. fides/ui-build/static/admin/_next/static/chunks/pages/consent/{reporting-44aa77149d71a6fe.js → reporting-b65b5ab73dfcb801.js} +1 -1
  73. fides/ui-build/static/admin/_next/static/chunks/pages/{consent-23ab7bd613a0ad53.js → consent-87c06e0daf2b2e87.js} +1 -1
  74. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-dae11464a091537f.js → [projectUrn]-c956a3faed9f922c.js} +1 -1
  75. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{projects-7442023478422295.js → projects-691e19bdd29b8c3b.js} +1 -1
  76. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{resources-d8db234a44a2ddf4.js → resources-7648bbd4f6711e4d.js} +1 -1
  77. fides/ui-build/static/admin/_next/static/chunks/pages/{data-catalog-5597d2e691313bb0.js → data-catalog-b1616ecfd86a2e2e.js} +1 -1
  78. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/{[systemId]-da06d05d255d0cd0.js → [systemId]-052028439e802c76.js} +1 -1
  79. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/{[monitorId]-895591fe32af0f4c.js → [monitorId]-99d3a2197ab8a9b0.js} +1 -1
  80. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{action-center-a932a39e29ac3489.js → action-center-a694e71d11bed653.js} +1 -1
  81. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{activity-2cfdf4d55a7594ba.js → activity-312edbab3c17f26a.js} +1 -1
  82. fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-07881d1a5fc03d41.js → datamap-e8bfa1a3a8b84b6d.js} +1 -1
  83. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/{[...subfieldNames]-57be9d40c67b0acb.js → [...subfieldNames]-f976632b92911072.js} +1 -1
  84. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/{[collectionName]-bd78d6c6264e2467.js → [collectionName]-9ffa34d7ee7b2872.js} +1 -1
  85. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{[datasetId]-3c9103487b55e76f.js → [datasetId]-6e65dcdd692b4625.js} +1 -1
  86. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{new-e30a546a8cfb6658.js → new-423f08db5d9adc9a.js} +1 -1
  87. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-2bd2b941ad8f87b1.js +1 -0
  88. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-34958fe8183d9479.js → [id]-1b7bfb005fd8e4e1.js} +1 -1
  89. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-761294dbaf59bbe1.js → new-b737165f7752f039.js} +1 -1
  90. fides/ui-build/static/admin/_next/static/chunks/pages/{datastore-connection-59abd36059863e05.js → datastore-connection-6b02666ce735e092.js} +1 -1
  91. fides/ui-build/static/admin/_next/static/chunks/pages/{index-ae100a873eb66d59.js → index-99ad22eddbb6b7f2.js} +1 -1
  92. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-97f9e9b2822d2576.js +1 -0
  93. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-4ce156e73fe3608f.js +1 -0
  94. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-2aada2c7b9156053.js → [id]-8970d29f1710f486.js} +1 -1
  95. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-fbb7b0c43dedf072.js → add-template-db905b79b189989c.js} +1 -1
  96. fides/ui-build/static/admin/_next/static/chunks/pages/{messaging-7230d7ee21368cef.js → messaging-10084105bae43a19.js} +1 -1
  97. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{ant-components-7c234412502f8102.js → ant-components-cf7c0b3782c0c7a6.js} +1 -1
  98. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{AntForm-72791aab60f3a4bf.js → AntForm-8cf5c6bb7f4595eb.js} +1 -1
  99. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikAntFormItem-da7d11d6146fa746.js → FormikAntFormItem-01904c9c8521ef1c.js} +1 -1
  100. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikControlled-3045d24344e99017.js → FormikControlled-ed8c23307b2b6868.js} +1 -1
  101. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikField-5b5b165d3f41a1de.js → FormikField-3ec8e1811906a1d2.js} +1 -1
  102. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{forms-3afd8b6ba6234366.js → forms-18fc8b3a8ccfc80b.js} +1 -1
  103. fides/ui-build/static/admin/_next/static/chunks/pages/poc/{table-migration-52d50286216bcb8c.js → table-migration-372166dc1d6268ea.js} +1 -1
  104. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-104f33c424613732.js +1 -0
  105. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{messaging-535b6e5003d892eb.js → messaging-a29479bc35b00f45.js} +1 -1
  106. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/{storage-7ded688a1e832c63.js → storage-10e2886bc4d4f62b.js} +1 -1
  107. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-08e0863d432b3348.js → configure-340150cac5bf8e4a.js} +1 -1
  108. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-b1772281866cb827.js +1 -0
  109. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-b8dcb1f5213521ef.js → [id]-d9cdc82249593440.js} +1 -1
  110. fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-7d8418bb7cb9e1fd.js → add-property-d2e0236ab65b1fb9.js} +1 -1
  111. fides/ui-build/static/admin/_next/static/chunks/pages/{properties-537003822f360ae7.js → properties-156bd0e36831ed04.js} +1 -1
  112. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/{datamap-ac25749935da453b.js → datamap-49e5607055db1bee.js} +1 -1
  113. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/{alpha-647d59bb0aa060bf.js → alpha-68697c49b290ba50.js} +1 -1
  114. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{about-73adc03fe0182e3f.js → about-a45a5b9f78c64e27.js} +1 -1
  115. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/{[purpose_id]-ffa9e9e79ad75828.js → [purpose_id]-c54d90dd4ac04de3.js} +1 -1
  116. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{consent-4fb6c8c4bd9cdb3f.js → consent-2ecf179f6587e3b3.js} +1 -1
  117. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{custom-fields-94c1b7bfc6cec4d2.js → custom-fields-80bf043deb37a20c.js} +1 -1
  118. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-e9838b8e49e64e57.js → domain-records-c2ef327dc49618e9.js} +1 -1
  119. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domains-0de16778ad2f8865.js → domains-bdc7ee59802c2e4a.js} +1 -1
  120. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-aac71677024210ad.js → email-templates-6af619d1d57bb99c.js} +1 -1
  121. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-f43e238571b21643.js → locations-09cb08245844c601.js} +1 -1
  122. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-f5e0a34f6ae473ad.js → organization-d9e7feee568f6e35.js} +1 -1
  123. fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-05d3c86ca3ca4d5d.js → regulations-7cfbb9149f96961a.js} +1 -1
  124. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-31fcf7b52d8028b0.js → test-datasets-9f5912cb2f471fdf.js} +1 -1
  125. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-6db01a1afe2f82d5.js → [id]-0252e5f648c5e3f8.js} +1 -1
  126. fides/ui-build/static/admin/_next/static/chunks/pages/{systems-8ec7472a7032301f.js → systems-5332864c5e8595dc.js} +1 -1
  127. fides/ui-build/static/admin/_next/static/chunks/pages/{taxonomy-84caae0fc02f8ae1.js → taxonomy-80f4ab8b7b6e7f5e.js} +1 -1
  128. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-e452541827698b1f.js → [id]-e607e07bd1ef2da0.js} +1 -1
  129. fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-530be849391d2425.js → user-management-d539f1c4e6adf73a.js} +1 -1
  130. fides/ui-build/static/admin/_next/static/chunks/webpack-8fc1c717e1c0f7ae.js +1 -0
  131. fides/ui-build/static/admin/_next/static/css/5f8af79f94072e0f.css +1 -0
  132. fides/ui-build/static/admin/_next/static/hww-k841LVyuYWaSAg-CK/_buildManifest.js +1 -0
  133. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  134. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  135. fides/ui-build/static/admin/add-systems.html +1 -1
  136. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  137. fides/ui-build/static/admin/consent/configure.html +1 -1
  138. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  139. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  140. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  141. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  142. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  143. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  144. fides/ui-build/static/admin/consent/properties.html +1 -1
  145. fides/ui-build/static/admin/consent/reporting.html +1 -1
  146. fides/ui-build/static/admin/consent.html +1 -1
  147. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  148. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  149. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  150. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  151. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  152. fides/ui-build/static/admin/data-catalog.html +1 -1
  153. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  154. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  155. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  156. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  157. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  158. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  159. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  160. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  161. fides/ui-build/static/admin/datamap.html +1 -1
  162. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  163. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  164. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  165. fides/ui-build/static/admin/dataset/new.html +1 -1
  166. fides/ui-build/static/admin/dataset.html +1 -1
  167. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  168. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  169. fides/ui-build/static/admin/datastore-connection.html +1 -1
  170. fides/ui-build/static/admin/images/connector-logos/manual_tasks.svg +25 -0
  171. fides/ui-build/static/admin/index.html +1 -1
  172. fides/ui-build/static/admin/integrations/[id].html +1 -1
  173. fides/ui-build/static/admin/integrations.html +1 -1
  174. fides/ui-build/static/admin/lib/fides-headless.js +1 -1
  175. fides/ui-build/static/admin/lib/fides-preview.js +1 -1
  176. fides/ui-build/static/admin/lib/fides-tcf.js +3 -3
  177. fides/ui-build/static/admin/lib/fides.js +3 -3
  178. fides/ui-build/static/admin/login/[provider].html +1 -1
  179. fides/ui-build/static/admin/login.html +1 -1
  180. fides/ui-build/static/admin/messaging/[id].html +1 -1
  181. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  182. fides/ui-build/static/admin/messaging.html +1 -1
  183. fides/ui-build/static/admin/poc/ant-components.html +1 -1
  184. fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
  185. fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
  186. fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
  187. fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
  188. fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
  189. fides/ui-build/static/admin/poc/forms.html +1 -1
  190. fides/ui-build/static/admin/poc/table-migration.html +1 -1
  191. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  192. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  193. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  194. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  195. fides/ui-build/static/admin/privacy-requests.html +1 -1
  196. fides/ui-build/static/admin/properties/[id].html +1 -1
  197. fides/ui-build/static/admin/properties/add-property.html +1 -1
  198. fides/ui-build/static/admin/properties.html +1 -1
  199. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  200. fides/ui-build/static/admin/settings/about/alpha.html +1 -1
  201. fides/ui-build/static/admin/settings/about.html +1 -1
  202. fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
  203. fides/ui-build/static/admin/settings/consent.html +1 -1
  204. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  205. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  206. fides/ui-build/static/admin/settings/domains.html +1 -1
  207. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  208. fides/ui-build/static/admin/settings/locations.html +1 -1
  209. fides/ui-build/static/admin/settings/organization.html +1 -1
  210. fides/ui-build/static/admin/settings/regulations.html +1 -1
  211. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  212. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  213. fides/ui-build/static/admin/systems.html +1 -1
  214. fides/ui-build/static/admin/taxonomy.html +1 -1
  215. fides/ui-build/static/admin/user-management/new.html +1 -1
  216. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  217. fides/ui-build/static/admin/user-management.html +1 -1
  218. fides/ui-build/static/admin/_next/static/chunks/1169-ae67fde0c6d69abc.js +0 -1
  219. fides/ui-build/static/admin/_next/static/chunks/3450-4e472b9e2754fa47.js +0 -1
  220. fides/ui-build/static/admin/_next/static/chunks/4121-10bfa009892586fa.js +0 -1
  221. fides/ui-build/static/admin/_next/static/chunks/6662-d8ae12f69d325004.js +0 -1
  222. fides/ui-build/static/admin/_next/static/chunks/827-c6fe34fb336467ae.js +0 -1
  223. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-500610c0b60f9e7e.js +0 -1
  224. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-8eee4d0314c83e50.js +0 -1
  225. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-bf3b87b0dd702551.js +0 -1
  226. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-00fb442c4adb7371.js +0 -1
  227. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-c8b02ae92dd7e45b.js +0 -1
  228. fides/ui-build/static/admin/_next/static/chunks/webpack-e25ccaae1ef867a2.js +0 -1
  229. fides/ui-build/static/admin/_next/static/css/23391a3311f80cfe.css +0 -1
  230. fides/ui-build/static/admin/_next/static/z7GzAZhoGiO521zm7WPYX/_buildManifest.js +0 -1
  231. {ethyca_fides-2.64.6b1.dist-info → ethyca_fides-2.65.0.dist-info}/WHEEL +0 -0
  232. {ethyca_fides-2.64.6b1.dist-info → ethyca_fides-2.65.0.dist-info}/entry_points.txt +0 -0
  233. {ethyca_fides-2.64.6b1.dist-info → ethyca_fides-2.65.0.dist-info}/licenses/LICENSE +0 -0
  234. {ethyca_fides-2.64.6b1.dist-info → ethyca_fides-2.65.0.dist-info}/top_level.txt +0 -0
  235. /fides/ui-build/static/admin/_next/static/{z7GzAZhoGiO521zm7WPYX → hww-k841LVyuYWaSAg-CK}/_ssgManifest.js +0 -0
fides/_version.py CHANGED
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2025-07-02T08:50:36-0700",
11
+ "date": "2025-07-08T13:15:47-0300",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "5b2b01716a352fdf042c622bf1b996a7490b400b",
15
- "version": "2.64.6b1"
14
+ "full-revisionid": "34ee2ee50c7518572e66a4441078263e59ba4030",
15
+ "version": "2.65.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -0,0 +1,28 @@
1
+ """add user_id to manual_task_log
2
+
3
+ Revision ID: 641f6bcd424f
4
+ Revises: 41a634d8c669
5
+ Create Date: 2025-07-02 03:19:40.171201
6
+
7
+ """
8
+
9
+ import sqlalchemy as sa
10
+ from alembic import op
11
+
12
+ # revision identifiers, used by Alembic.
13
+ revision = "641f6bcd424f"
14
+ down_revision = "41a634d8c669"
15
+ branch_labels = None
16
+ depends_on = None
17
+
18
+
19
+ def upgrade():
20
+ op.add_column("manual_task_log", sa.Column("user_id", sa.String(), nullable=True))
21
+ op.create_index(
22
+ op.f("ix_manual_task_log_user_id"), "manual_task_log", ["user_id"], unique=False
23
+ )
24
+
25
+
26
+ def downgrade():
27
+ op.drop_index(op.f("ix_manual_task_log_user_id"), table_name="manual_task_log")
28
+ op.drop_column("manual_task_log", "user_id")
@@ -1,6 +1,8 @@
1
+ from functools import partial
1
2
  from typing import Dict, List, Optional, Type, Union
2
3
 
3
4
  from fastapi import Depends, HTTPException, Query, Response, Security
5
+ from fastapi.concurrency import run_in_threadpool
4
6
  from fastapi.encoders import jsonable_encoder
5
7
  from fastapi.responses import JSONResponse
6
8
  from fastapi_pagination import Page, Params
@@ -224,9 +226,17 @@ async def list_dataset_paginated(
224
226
 
225
227
  pagination_params = Params(page=page or 1, size=size or 50)
226
228
  results = await async_paginate(db, filtered_query, pagination_params)
227
- results.items = [ # type: ignore[attr-defined]
228
- DatasetResponse.model_validate(result.__dict__) for result in results.items # type: ignore[attr-defined]
229
- ]
229
+
230
+ validated_items = []
231
+ for result in results.items: # type: ignore[attr-defined]
232
+ # run pydantic validation in a threadpool to avoid blocking the main thread
233
+ validated_item = await run_in_threadpool(
234
+ partial(DatasetResponse.model_validate, result.__dict__)
235
+ )
236
+ validated_items.append(validated_item)
237
+
238
+ results.items = validated_items # type: ignore[attr-defined]
239
+
230
240
  return results
231
241
 
232
242
 
@@ -8,6 +8,7 @@ from fides.api.email_templates.template_names import (
8
8
  CONSENT_REQUEST_EMAIL_FULFILLMENT,
9
9
  CONSENT_REQUEST_VERIFICATION_TEMPLATE,
10
10
  EMAIL_ERASURE_REQUEST_FULFILLMENT,
11
+ EXTERNAL_USER_WELCOME,
11
12
  PRIVACY_REQUEST_COMPLETE_ACCESS_TEMPLATE,
12
13
  PRIVACY_REQUEST_COMPLETE_DELETION_TEMPLATE,
13
14
  PRIVACY_REQUEST_ERROR_NOTIFICATION_TEMPLATE,
@@ -29,7 +30,7 @@ template_env = Environment(
29
30
  )
30
31
 
31
32
 
32
- def get_email_template( # pylint: disable=too-many-return-statements
33
+ def get_email_template( # pylint: disable=too-many-return-statements, too-many-branches
33
34
  action_type: MessagingActionType,
34
35
  ) -> Template:
35
36
  if action_type == MessagingActionType.CONSENT_REQUEST:
@@ -56,6 +57,8 @@ def get_email_template( # pylint: disable=too-many-return-statements
56
57
  return template_env.get_template(TEST_MESSAGE_TEMPLATE)
57
58
  if action_type == MessagingActionType.USER_INVITE:
58
59
  return template_env.get_template(USER_INVITE)
60
+ if action_type == MessagingActionType.EXTERNAL_USER_WELCOME:
61
+ return template_env.get_template(EXTERNAL_USER_WELCOME)
59
62
 
60
63
  logger.error("No corresponding template linked to the {}", action_type)
61
64
  raise EmailTemplateUnhandledActionType(
@@ -10,3 +10,4 @@ PRIVACY_REQUEST_REVIEW_DENY_TEMPLATE = "privacy_request_review_deny.html"
10
10
  PRIVACY_REQUEST_REVIEW_APPROVE_TEMPLATE = "privacy_request_review_approve.html"
11
11
  TEST_MESSAGE_TEMPLATE = "test_message.html"
12
12
  USER_INVITE = "user_invite.html"
13
+ EXTERNAL_USER_WELCOME = "external_user_welcome.html"
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <title>Welcome to Privacy Center</title>
6
+ </head>
7
+ <body>
8
+ <main>
9
+ <p>Hello {{ display_name }},</p>
10
+
11
+ <p>An account has been created for you by the privacy team at {{ org_name }} so that you can assist them in responding to data subject requests, as required by the GDPR and many US state laws, for users that have data in your systems.</p>
12
+
13
+ <p>A portal is available to view and take action on these requests at: <a href="{{ portal_link }}">{{ portal_link }}</a>. Through this portal you can upload or provide user data for users who have requested a copy of their information and attest that users have been removed from your system in the case of an erasure request.</p>
14
+
15
+ <p>The provided link is valid for 30 days and you will be asked to verify your email address each time you access the portal.</p>
16
+
17
+ <p>If you have any questions, please reach out first to your contacts at: {{ org_name }}</p>
18
+
19
+ <p>Regards,<br/>
20
+ {{ org_name }} Privacy Team</p>
21
+ </main>
22
+ </body>
23
+ </html>
@@ -19,16 +19,16 @@ CONFIG = get_config()
19
19
  if TYPE_CHECKING:
20
20
  from fides.api.models.fides_user import FidesUser
21
21
 
22
- # Access links stay active for 45 days - the same as the DSR expiration. A new link is generated for each email.
22
+ # Access links stay active for 30 days for external login functionality. A new link is generated for each email.
23
23
  # The emails are created for new DSRs which are assigned to the respondent.
24
- ACCESS_LINK_TTL_DAYS = 45
24
+ ACCESS_LINK_TTL_DAYS = 30
25
25
 
26
26
 
27
27
  class FidesUserRespondentEmailVerification(Base, IdentityVerificationMixin):
28
28
  """Model for handling email verification for external respondents.
29
29
 
30
30
  This handles two types of verification:
31
- 1. Access links - long-lived (45 days) for initial access
31
+ 1. Access links - long-lived (30 days) for initial access
32
32
  2. Verification codes - short-lived (1 hour) for actual verification
33
33
 
34
34
  When an email is sent to an external respondent, a new verification is created with a new access token is created.
@@ -20,6 +20,7 @@ from sqlalchemy.sql import func
20
20
 
21
21
  from fides.api.db.base_class import Base, FidesBase
22
22
  from fides.api.db.util import EnumColumn
23
+ from fides.api.request_context import get_user_id
23
24
  from fides.api.schemas.base_class import FidesSchema
24
25
 
25
26
  if TYPE_CHECKING:
@@ -880,6 +881,10 @@ class ManualTaskLog(Base):
880
881
  ForeignKey("manual_task_instance.id", ondelete="CASCADE"),
881
882
  nullable=True,
882
883
  )
884
+ # The user responsible for the action being logged. This may be `None`
885
+ # for system-initiated events or for legacy records created before this
886
+ # column existed.
887
+ user_id = Column(String, nullable=True, index=True)
883
888
  status = Column(String, nullable=False)
884
889
  message = Column(String, nullable=True)
885
890
  details = Column(JSONB, nullable=True)
@@ -890,6 +895,7 @@ class ManualTaskLog(Base):
890
895
  Index("ix_manual_task_log_instance_id", "instance_id"),
891
896
  Index("ix_manual_task_log_status", "status"),
892
897
  Index("ix_manual_task_log_task_id", "task_id"),
898
+ Index("ix_manual_task_log_user_id", "user_id"),
893
899
  )
894
900
 
895
901
  # Relationships
@@ -908,6 +914,7 @@ class ManualTaskLog(Base):
908
914
  task_id: str,
909
915
  status: "ManualTaskLogStatus",
910
916
  message: str,
917
+ user_id: Optional[str] = None,
911
918
  config_id: Optional[str] = None,
912
919
  instance_id: Optional[str] = None,
913
920
  details: Optional[dict[str, Any]] = None,
@@ -921,10 +928,12 @@ class ManualTaskLog(Base):
921
928
  message: Optional message describing the event
922
929
  details: Optional additional details about the event
923
930
  """
931
+
924
932
  data = {
925
933
  "task_id": task_id,
926
934
  "config_id": config_id,
927
935
  "instance_id": instance_id,
936
+ "user_id": user_id or get_user_id(),
928
937
  "status": status,
929
938
  "message": message,
930
939
  "details": details,
@@ -937,6 +946,7 @@ class ManualTaskLog(Base):
937
946
  db: Session,
938
947
  task_id: str,
939
948
  message: str,
949
+ user_id: Optional[str] = None,
940
950
  config_id: Optional[str] = None,
941
951
  instance_id: Optional[str] = None,
942
952
  details: Optional[dict[str, Any]] = None,
@@ -954,12 +964,14 @@ class ManualTaskLog(Base):
954
964
  Returns:
955
965
  The created error log entry
956
966
  """
967
+
957
968
  return cls.create_log(
958
969
  db=db,
959
970
  status=ManualTaskLogStatus.error,
960
971
  task_id=task_id,
961
972
  config_id=config_id,
962
973
  instance_id=instance_id,
974
+ user_id=user_id or get_user_id(),
963
975
  message=message,
964
976
  details=details,
965
977
  )
fides/api/oauth/utils.py CHANGED
@@ -31,6 +31,7 @@ from fides.api.models.policy import PolicyPreWebhook
31
31
  from fides.api.models.pre_approval_webhook import PreApprovalWebhook
32
32
  from fides.api.models.privacy_request import RequestTask
33
33
  from fides.api.oauth.roles import get_scopes_from_roles
34
+ from fides.api.request_context import set_user_id
34
35
  from fides.api.schemas.external_https import RequestTaskJWE, WebhookJWE
35
36
  from fides.api.schemas.oauth import OAuth2ClientCredentialsBearer
36
37
  from fides.common.api.v1.urn_registry import TOKEN, V1_URL_PREFIX
@@ -325,6 +326,16 @@ def extract_token_and_load_client(
325
326
  logger.debug("Auth token belongs to an invalid client_id.")
326
327
  raise AuthorizationError(detail="Not Authorized for this action")
327
328
 
329
+ # Populate request-scoped context with the authenticated user identifier.
330
+ # Prefer the linked user_id; fall back to the client id when this is the
331
+ # special root client (which has no associated FidesUser row).
332
+ ctx_user_id = client.user_id
333
+ if not ctx_user_id and client.id == CONFIG.security.oauth_root_client_id:
334
+ ctx_user_id = CONFIG.security.oauth_root_client_id
335
+
336
+ if ctx_user_id:
337
+ set_user_id(ctx_user_id)
338
+
328
339
  return token_data, client
329
340
 
330
341
 
@@ -0,0 +1,76 @@
1
+ """
2
+ Utilities for storing and accessing request-scoped context that must be
3
+ accessible across the entire application stack (endpoints -> services ->
4
+ helpers -> decorators) without having to thread additional parameters through
5
+ all call-sites.
6
+
7
+ Currently we only capture the authenticated `user_id` but additional fields
8
+ (e.g. correlation_id, locale, feature_flags) can be added in the future by
9
+ expanding the `RequestContext` dataclass.
10
+
11
+ A `contextvars.ContextVar` is used instead of a module-level global to ensure
12
+ that values are local to the current execution context (async task, thread or
13
+ Celery worker) and therefore safe for concurrent workloads.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import contextvars
19
+ from dataclasses import dataclass
20
+ from typing import Any, Optional
21
+
22
+ __all__ = [
23
+ "get_user_id",
24
+ "set_user_id",
25
+ "reset_request_context",
26
+ ]
27
+
28
+
29
+ @dataclass
30
+ class RequestContext:
31
+ user_id: Optional[str] = None
32
+
33
+
34
+ # A single ContextVar holding the current request context.
35
+ _ctx: contextvars.ContextVar[RequestContext] = contextvars.ContextVar(
36
+ "request_context",
37
+ default=RequestContext(),
38
+ )
39
+
40
+
41
+ def get_request_context() -> RequestContext:
42
+ """Return the current `RequestContext` for this request.
43
+
44
+ - The context is populated during authentication by `extract_token_and_load_client()`,
45
+ which calls `fides.api.request_context.set_request_context` with
46
+ the authenticated `user_id`.
47
+ - A `ContextVar` keeps the data isolated per request. Each coroutine
48
+ or thread sees its own copy and it is discarded at the end of the request.
49
+ - The returned object is the live context; treat it as read-only and use
50
+ `set_request_context` to mutate values.
51
+ """
52
+ return _ctx.get()
53
+
54
+
55
+ def set_request_context(**kwargs: Any) -> None:
56
+ """Mutate the current context in place using `key=value` pairs."""
57
+ ctx = _ctx.get()
58
+ for key, value in kwargs.items():
59
+ if hasattr(ctx, key):
60
+ setattr(ctx, key, value)
61
+
62
+
63
+ def reset_request_context() -> None:
64
+ """Remove all context, mainly for test clean-up."""
65
+ _ctx.set(RequestContext())
66
+
67
+
68
+ def get_user_id() -> Optional[str]:
69
+ """Return the user_id from the current request context."""
70
+ ctx = get_request_context()
71
+ return ctx.user_id
72
+
73
+
74
+ def set_user_id(user_id: str) -> None:
75
+ """Set the user_id in the current request context."""
76
+ set_request_context(user_id=user_id)
@@ -69,6 +69,7 @@ class MessagingActionType(str, Enum):
69
69
  PRIVACY_REQUEST_REVIEW_DENY = "privacy_request_review_deny"
70
70
  PRIVACY_REQUEST_REVIEW_APPROVE = "privacy_request_review_approve"
71
71
  USER_INVITE = "user_invite"
72
+ EXTERNAL_USER_WELCOME = "external_user_welcome"
72
73
  TEST_MESSAGE = "test_message"
73
74
 
74
75
 
@@ -182,6 +183,17 @@ class UserInviteBodyParams(BaseModel):
182
183
  invite_code: str
183
184
 
184
185
 
186
+ class ExternalUserWelcomeBodyParams(BaseModel):
187
+ """Body params required to send a welcome email to external users"""
188
+
189
+ username: str
190
+ first_name: Optional[str] = None
191
+ last_name: Optional[str] = None
192
+ privacy_center_url: str
193
+ access_token: str
194
+ org_name: str
195
+
196
+
185
197
  class FidesopsMessage(
186
198
  BaseModel,
187
199
  ):
@@ -198,6 +210,7 @@ class FidesopsMessage(
198
210
  ErasureRequestBodyParams,
199
211
  ErrorNotificationBodyParams,
200
212
  UserInviteBodyParams,
213
+ ExternalUserWelcomeBodyParams,
201
214
  ]
202
215
  ] = None
203
216
 
@@ -217,6 +230,7 @@ class FidesopsMessage(
217
230
  MessagingActionType.MESSAGE_ERASURE_REQUEST_FULFILLMENT: ErasureRequestBodyParams,
218
231
  MessagingActionType.PRIVACY_REQUEST_ERROR_NOTIFICATION: ErrorNotificationBodyParams,
219
232
  MessagingActionType.USER_INVITE: UserInviteBodyParams,
233
+ MessagingActionType.EXTERNAL_USER_WELCOME: ExternalUserWelcomeBodyParams,
220
234
  }
221
235
 
222
236
  valid_body_params = valid_body_params_for_action_type.get(
@@ -30,6 +30,12 @@ class FilterPostProcessorConfiguration(StrategyConfiguration):
30
30
  case_sensitive: bool = True
31
31
 
32
32
 
33
+ class ExtractForExecutionLogPostProcessorConfiguration(StrategyConfiguration):
34
+ """Configuration for extracting data from response body and adding to execution log messages"""
35
+
36
+ path: Optional[str] = None
37
+
38
+
33
39
  class OffsetPaginationConfiguration(StrategyConfiguration):
34
40
  """
35
41
  Increases the value of the query param `incremental_param` by the `increment_by` until the `limit` is hit
@@ -423,6 +423,7 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
423
423
  response_data,
424
424
  identity_data,
425
425
  cast(Optional[List[PostProcessorStrategy]], saas_request.postprocessors),
426
+ response,
426
427
  )
427
428
 
428
429
  logger.info(
@@ -456,6 +457,7 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
456
457
  response_data: Union[List[Dict[str, Any]], Dict[str, Any]],
457
458
  identity_data: Dict[str, Any],
458
459
  postprocessors: Optional[List[PostProcessorStrategy]],
460
+ response: Optional[Response] = None,
459
461
  ) -> List[Row]:
460
462
  """
461
463
  Runs the raw response through all available postprocessors for the request,
@@ -481,7 +483,9 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
481
483
  processed_data,
482
484
  identity_data,
483
485
  privacy_request,
486
+ response,
484
487
  )
488
+
485
489
  except Exception as exc:
486
490
  raise PostProcessingException(
487
491
  f"Exception occurred during the '{postprocessor.strategy}' postprocessor " # type: ignore
@@ -567,6 +571,7 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
567
571
  rows,
568
572
  privacy_request.get_cached_identity_data(),
569
573
  cast(Optional[List[PostProcessorStrategy]], masking_request.postprocessors),
574
+ None,
570
575
  )
571
576
 
572
577
  client = self.create_client()
@@ -584,9 +589,46 @@ class SaaSConnector(BaseConnector[AuthenticatedClient], Contextualizable):
584
589
  )
585
590
  continue
586
591
  raise exc
587
- client.send(prepared_request, masking_request.ignore_errors)
592
+ response = client.send(prepared_request, masking_request.ignore_errors)
588
593
  rows_updated += 1
589
594
 
595
+ # Run post-processors against the response from the masking request so that
596
+ # processors such as `extract_for_execution_log` can inspect the API
597
+ # response body (e.g. confirmation, ticket IDs, etc.). We ignore the
598
+ # returned rows because masking responses are not used downstream.
599
+ try:
600
+ handled_response = self._handle_errored_response(
601
+ masking_request, response
602
+ )
603
+ response_data = self._unwrap_response_data(
604
+ masking_request, handled_response
605
+ )
606
+
607
+ # Only attempt post-processing if we have post-processors and the response body
608
+ # is JSON-serializable (dict or list of dicts).
609
+ if masking_request.postprocessors and isinstance(
610
+ response_data, (dict, list)
611
+ ):
612
+ self.process_response_data(
613
+ response_data,
614
+ privacy_request.get_cached_identity_data(),
615
+ cast(
616
+ Optional[List[PostProcessorStrategy]],
617
+ masking_request.postprocessors,
618
+ ),
619
+ handled_response,
620
+ )
621
+ except (
622
+ PostProcessingException,
623
+ Exception,
624
+ ) as exc: # pylint: disable=broad-except
625
+ # We do not want a post-processing failure to prevent the masking
626
+ # operation itself from succeeding.
627
+ logger.warning(
628
+ "Post-processing of masking request response failed: {}",
629
+ exc,
630
+ )
631
+
590
632
  self.unset_connector_state()
591
633
 
592
634
  awaiting_async_callback: bool = bool(
@@ -0,0 +1,59 @@
1
+ """
2
+ Execution context for collecting log messages during privacy request processing.
3
+
4
+ Uses Python's contextvars for thread-safe, execution-scoped message collection.
5
+ """
6
+
7
+ import contextvars
8
+ from contextlib import contextmanager
9
+ from typing import Generator, List, Optional
10
+
11
+ from loguru import logger
12
+
13
+ # Context variable for current execution messages
14
+ _execution_messages: contextvars.ContextVar[Optional[List[str]]] = (
15
+ contextvars.ContextVar("execution_messages")
16
+ )
17
+
18
+
19
+ @contextmanager
20
+ def collect_execution_log_messages() -> Generator[List[str], None, None]:
21
+ """
22
+ Context manager for collecting execution log messages.
23
+
24
+ Usage:
25
+ with collect_execution_log_messages() as messages:
26
+ # ... do work that calls add_execution_log_message()
27
+ pass
28
+ # messages now contains all collected messages
29
+
30
+ Returns:
31
+ List[str]: Messages collected during execution
32
+ """
33
+ messages: List[str] = []
34
+ token = _execution_messages.set(messages)
35
+ try:
36
+ yield messages
37
+ finally:
38
+ _execution_messages.reset(token)
39
+
40
+
41
+ def add_execution_log_message(message: str) -> None:
42
+ """Add a message to the current execution context"""
43
+ try:
44
+ messages = _execution_messages.get()
45
+ if messages is not None and message.strip():
46
+ messages.append(message.strip())
47
+ except LookupError:
48
+ logger.error(
49
+ f"Attempted to call add_execution_log_message outside of execution context, unable to add message: {message}"
50
+ )
51
+
52
+
53
+ def get_execution_log_messages() -> List[str]:
54
+ """Get messages from current execution context (for testing/debugging)"""
55
+ try:
56
+ messages = _execution_messages.get()
57
+ return messages.copy() if messages is not None else []
58
+ except LookupError:
59
+ return []
@@ -26,6 +26,7 @@ from fides.api.schemas.messaging.messaging import (
26
26
  EmailForActionType,
27
27
  ErasureRequestBodyParams,
28
28
  ErrorNotificationBodyParams,
29
+ ExternalUserWelcomeBodyParams,
29
30
  FidesopsMessage,
30
31
  MessagingActionType,
31
32
  MessagingMethod,
@@ -176,6 +177,7 @@ def dispatch_message(
176
177
  ErasureRequestBodyParams,
177
178
  UserInviteBodyParams,
178
179
  ErrorNotificationBodyParams,
180
+ ExternalUserWelcomeBodyParams,
179
181
  ]
180
182
  ] = None,
181
183
  subject_override: Optional[str] = None,
@@ -351,7 +353,7 @@ def _render(template_str: str, variables: Optional[Dict] = None) -> str:
351
353
  return template_str
352
354
 
353
355
 
354
- def _build_email( # pylint: disable=too-many-return-statements
356
+ def _build_email( # pylint: disable=too-many-return-statements, too-many-branches
355
357
  config_proxy: ConfigProxy,
356
358
  action_type: MessagingActionType,
357
359
  body_params: Any,
@@ -463,6 +465,36 @@ def _build_email( # pylint: disable=too-many-return-statements
463
465
  }
464
466
  ),
465
467
  )
468
+ if action_type == MessagingActionType.EXTERNAL_USER_WELCOME:
469
+ base_template = get_email_template(action_type)
470
+ # Generate display name for personalization
471
+ display_name = body_params.username
472
+ if body_params.first_name:
473
+ display_name = body_params.first_name
474
+ if body_params.last_name:
475
+ display_name = f"{body_params.first_name} {body_params.last_name}"
476
+
477
+ portal_link = (
478
+ f"{body_params.privacy_center_url}?access_token={body_params.access_token}"
479
+ )
480
+
481
+ variables = {
482
+ "username": body_params.username,
483
+ "display_name": display_name,
484
+ "first_name": body_params.first_name,
485
+ "last_name": body_params.last_name,
486
+ "org_name": body_params.org_name,
487
+ "portal_link": portal_link,
488
+ "privacy_center_url": body_params.privacy_center_url,
489
+ "access_token": body_params.access_token,
490
+ }
491
+
492
+ return EmailForActionType(
493
+ subject="Welcome to our Privacy Center",
494
+ body=base_template.render(variables),
495
+ template_variables=variables,
496
+ )
497
+
466
498
  logger.error("Message action type {} is not implemented", action_type)
467
499
  raise MessageDispatchException(
468
500
  f"Message action type {action_type} is not implemented"
@@ -1,4 +1,5 @@
1
1
  from fides.api.service.processors.post_processor_strategy import (
2
+ post_processor_strategy_extract_for_execution_log,
2
3
  post_processor_strategy_filter,
3
4
  post_processor_strategy_unwrap,
4
5
  )
@@ -1,6 +1,8 @@
1
1
  from abc import abstractmethod
2
2
  from typing import Any, Dict, List, Optional, Union
3
3
 
4
+ from requests import Response
5
+
4
6
  from fides.api.models.privacy_request import PrivacyRequest
5
7
  from fides.api.service.strategy import Strategy
6
8
 
@@ -14,5 +16,13 @@ class PostProcessorStrategy(Strategy):
14
16
  data: Any,
15
17
  identity_data: Optional[Dict[str, Any]] = None,
16
18
  privacy_request: Optional[PrivacyRequest] = None,
19
+ response: Optional[Response] = None,
17
20
  ) -> Union[List[Dict[str, Any]], Dict[str, Any]]:
18
- """Process data from SaaS connector"""
21
+ """Process data from SaaS connector
22
+
23
+ Args:
24
+ data: The response data (potentially unwrapped/processed)
25
+ identity_data: Cached identity data for the request
26
+ privacy_request: The privacy request object
27
+ response: The raw HTTP response object (includes headers, status, etc.)
28
+ """