ethyca-fides 2.63.3rc0__py2.py3-none-any.whl → 2.64.1b0__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (362) hide show
  1. {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/METADATA +2 -2
  2. {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/RECORD +249 -242
  3. fides/_version.py +3 -3
  4. fides/api/alembic/migrations/versions/ba414a58ba90_create_manual_task_config_tables.py +121 -0
  5. fides/api/api/v1/endpoints/connection_endpoints.py +16 -3
  6. fides/api/api/v1/endpoints/oauth_endpoints.py +8 -2
  7. fides/api/db/base.py +4 -0
  8. fides/api/models/attachment.py +37 -23
  9. fides/api/models/manual_tasks/__init__.py +6 -0
  10. fides/api/models/manual_tasks/manual_task.py +11 -1
  11. fides/api/models/manual_tasks/manual_task_config.py +136 -0
  12. fides/api/models/manual_tasks/manual_task_log.py +13 -9
  13. fides/api/schemas/connection_configuration/connection_config.py +19 -4
  14. fides/api/schemas/manual_tasks/manual_task_config.py +311 -0
  15. fides/api/schemas/manual_tasks/manual_task_schemas.py +1 -1
  16. fides/api/schemas/manual_tasks/manual_task_status.py +1 -1
  17. fides/api/schemas/privacy_request.py +2 -0
  18. fides/api/service/connectors/query_configs/saas_query_config.py +15 -0
  19. fides/api/service/privacy_request/attachment_handling.py +132 -0
  20. fides/api/service/privacy_request/dsr_package/dsr_report_builder.py +264 -46
  21. fides/api/service/privacy_request/dsr_package/templates/attachments_index.html +33 -0
  22. fides/api/service/privacy_request/dsr_package/templates/collection_index.html +34 -9
  23. fides/api/service/privacy_request/dsr_package/templates/main.css +45 -2
  24. fides/api/service/privacy_request/dsr_package/templates/welcome.html +12 -8
  25. fides/api/service/privacy_request/request_runner_service.py +258 -139
  26. fides/api/service/storage/gcs.py +15 -3
  27. fides/api/service/storage/s3.py +28 -14
  28. fides/api/service/storage/util.py +45 -7
  29. fides/api/tasks/csv_utils.py +170 -0
  30. fides/api/tasks/encryption_utils.py +42 -0
  31. fides/api/tasks/storage.py +85 -91
  32. fides/api/util/cache.py +6 -3
  33. fides/api/util/saas_util.py +1 -0
  34. fides/config/redis_settings.py +105 -44
  35. fides/service/manual_tasks/manual_task_config_service.py +370 -0
  36. fides/service/manual_tasks/manual_task_service.py +231 -87
  37. fides/service/manual_tasks/utils.py +185 -0
  38. fides/ui-build/static/admin/404.html +1 -1
  39. fides/ui-build/static/admin/_next/static/chunks/1040-630c7f4284dc6f70.js +1 -0
  40. fides/ui-build/static/admin/_next/static/chunks/1100-d43cb04522a6505c.js +1 -0
  41. fides/ui-build/static/admin/_next/static/chunks/1316-6cc72a45ebf7ff81.js +1 -0
  42. fides/ui-build/static/admin/_next/static/chunks/1817-b4688ba5042ec687.js +1 -0
  43. fides/ui-build/static/admin/_next/static/chunks/2430-b480401d44c55416.js +1 -0
  44. fides/ui-build/static/admin/_next/static/chunks/2599-6c4d22e75028d8b6.js +1 -0
  45. fides/ui-build/static/admin/_next/static/chunks/2921-aabf41bf3d7573f9.js +1 -0
  46. fides/ui-build/static/admin/_next/static/chunks/3450-bdaeb35442d810b4.js +1 -0
  47. fides/ui-build/static/admin/_next/static/chunks/3505-a79256cd851dfab4.js +1 -0
  48. fides/ui-build/static/admin/_next/static/chunks/3513-8677ee280eaef0da.js +1 -0
  49. fides/ui-build/static/admin/_next/static/chunks/3855-0dec3e7d9e886550.js +1 -0
  50. fides/ui-build/static/admin/_next/static/chunks/3872-ffa16c2df7ef0ab6.js +1 -0
  51. fides/ui-build/static/admin/_next/static/chunks/3923-5d580fbb1dd6ae01.js +1 -0
  52. fides/ui-build/static/admin/_next/static/chunks/401-fceaae662cfca5a5.js +1 -0
  53. fides/ui-build/static/admin/_next/static/chunks/4060-71cd041e5a57ca5a.js +1 -0
  54. fides/ui-build/static/admin/_next/static/chunks/409-037cfc3f096150f0.js +1 -0
  55. fides/ui-build/static/admin/_next/static/chunks/4121-78a76e980acbd539.js +1 -0
  56. fides/ui-build/static/admin/_next/static/chunks/4230-1cdb7ea1be370ed3.js +1 -0
  57. fides/ui-build/static/admin/_next/static/chunks/431-f72599f01b98f07d.js +1 -0
  58. fides/ui-build/static/admin/_next/static/chunks/4481-f597a7cf03f8c9e1.js +1 -0
  59. fides/ui-build/static/admin/_next/static/chunks/5309-4511df9708d5a63c.js +1 -0
  60. fides/ui-build/static/admin/_next/static/chunks/5574-3cd33b3a6c937899.js +1 -0
  61. fides/ui-build/static/admin/_next/static/chunks/6277-3fb4c7fc790a6d20.js +1 -0
  62. fides/ui-build/static/admin/_next/static/chunks/6662-cb11881dcaabe5e2.js +1 -0
  63. fides/ui-build/static/admin/_next/static/chunks/6853-a4097260e402980e.js +1 -0
  64. fides/ui-build/static/admin/_next/static/chunks/6882-3cc73d407a088d7d.js +1 -0
  65. fides/ui-build/static/admin/_next/static/chunks/69-6889d6674c95e7b5.js +1 -0
  66. fides/ui-build/static/admin/_next/static/chunks/6954-13a25cef3a8fdd76.js +1 -0
  67. fides/ui-build/static/admin/_next/static/chunks/699-8ca44b0de9fa20f0.js +1 -0
  68. fides/ui-build/static/admin/_next/static/chunks/7553-a95939c32d54b5b7.js +1 -0
  69. fides/ui-build/static/admin/_next/static/chunks/79-5670e31eb65d0a53.js +1 -0
  70. fides/ui-build/static/admin/_next/static/chunks/796-9a6b13c838e25538.js +1 -0
  71. fides/ui-build/static/admin/_next/static/chunks/8433-adb1fcb29d82f1b7.js +1 -0
  72. fides/ui-build/static/admin/_next/static/chunks/9046-fdf53cc7e926a8c1.js +1 -0
  73. fides/ui-build/static/admin/_next/static/chunks/{905-8ab919e7b274ed50.js → 905-742074a074be1055.js} +2 -2
  74. fides/ui-build/static/admin/_next/static/chunks/9226-ba6587e46ec7659a.js +1 -0
  75. fides/ui-build/static/admin/_next/static/chunks/{9392.81edc11e3a175275.js → 9392.25024e070026343d.js} +1 -1
  76. fides/ui-build/static/admin/_next/static/chunks/9676.e60a53f1f5890847.js +1 -0
  77. fides/ui-build/static/admin/_next/static/chunks/9767-e49b065d03ce4e80.js +1 -0
  78. fides/ui-build/static/admin/_next/static/chunks/9951-f9ab5cac7e2c05ab.js +1 -0
  79. fides/ui-build/static/admin/_next/static/chunks/pages/404-ac2f0844e5c4b4cd.js +1 -0
  80. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-f70bffa5a7903c46.js → _app-8ec6e466f3373ac0.js} +10 -10
  81. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-0a5f2310ce6b1059.js +1 -0
  82. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/multiple-00cb904825aad7e3.js +1 -0
  83. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-587e21d14e0a5196.js +1 -0
  84. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/add-vendors-fa7305b88c1afd20.js +1 -0
  85. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-f140ec9d8e8a0f7a.js +1 -0
  86. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/[id]-0edb7c92518e7d21.js +1 -0
  87. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-d8d926f0735a2546.js +1 -0
  88. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/[id]-5c949f2e3cef2398.js +1 -0
  89. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/new-130155cfb4a0bcc7.js +1 -0
  90. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-1135ad8924d32c36.js +1 -0
  91. fides/ui-build/static/admin/_next/static/chunks/pages/consent/properties-776855e370414beb.js +1 -0
  92. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-21c23f75ff1135d9.js +1 -0
  93. fides/ui-build/static/admin/_next/static/chunks/pages/consent-4d5ea70a77df1bb8.js +1 -0
  94. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-18e3faf7963962e4.js → [resourceUrn]-c623d6f1a61c8ea9.js} +1 -1
  95. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-030ee304cbe5e530.js +1 -0
  96. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-cfac259a30641e68.js +1 -0
  97. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-7320524a47104798.js → [resourceUrn]-57bd5cdf784f059f.js} +1 -1
  98. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-7b5aec33da578745.js +1 -0
  99. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-c948f93c833d4358.js +1 -0
  100. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-333f53caab751428.js +1 -0
  101. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-27205f8457a1ecb0.js +1 -0
  102. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-20a1043f6a06198f.js +1 -0
  103. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-4c526db0c30c488a.js → [resourceUrn]-06edce289876dea1.js} +1 -1
  104. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-6f27dbb7c8edc69d.js → detection-faf326a6200637d0.js} +1 -1
  105. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-562d2b8ae90dd1f0.js → [resourceUrn]-64acf269256ee74f.js} +1 -1
  106. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-fe7f51502eda57c9.js → discovery-8c3e4be6d36da66d.js} +1 -1
  107. fides/ui-build/static/admin/_next/static/chunks/pages/datamap-fb50de22f83edd4a.js +1 -0
  108. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-41ab27c4195cfa93.js +1 -0
  109. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-6e2caba24b3e78c2.js +1 -0
  110. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-904d43e31157aa55.js +1 -0
  111. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-d4e31a1c4a58800e.js +1 -0
  112. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-8f7d16bc5e9229c8.js +1 -0
  113. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-4a33dd0371dbaebc.js +1 -0
  114. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-e88509346b2d2851.js +1 -0
  115. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-8f9b8890018e1ea5.js +1 -0
  116. fides/ui-build/static/admin/_next/static/chunks/pages/{fides-js-docs-80b241bf6cddb72e.js → fides-js-docs-5d8fd1af75f19e2f.js} +1 -1
  117. fides/ui-build/static/admin/_next/static/chunks/pages/index-1adb6bcb71701ac2.js +1 -0
  118. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-fdc2964fa7d1d8fd.js +1 -0
  119. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-adc286ff254e7f41.js +1 -0
  120. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/[id]-9b4d1d61c7c97509.js +1 -0
  121. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/add-template-f8fd4795e260887c.js +1 -0
  122. fides/ui-build/static/admin/_next/static/chunks/pages/messaging-aa744ae8b61e5ff2.js +1 -0
  123. fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-3407158757fb3627.js +1 -0
  124. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/AntForm-47e947c02ae90fd0.js +1 -0
  125. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikAntFormItem-24f9a44512ce8827.js +1 -0
  126. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikControlled-e567a69f8c37fb9a.js +1 -0
  127. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikField-35a33f9c7def2220.js +1 -0
  128. fides/ui-build/static/admin/_next/static/chunks/pages/poc/forms-780e18dde8e38099.js +1 -0
  129. fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-7a17dffa515e5560.js +1 -0
  130. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-91dd0039cc2b70bc.js +1 -0
  131. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-b01cbbaac34dadbc.js +1 -0
  132. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-a15410de7f1d0f84.js +1 -0
  133. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-1a1aa83a3f88844c.js +1 -0
  134. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-c4e1b69fb5bab61a.js +1 -0
  135. fides/ui-build/static/admin/_next/static/chunks/pages/properties/[id]-19737d4f21aadbee.js +1 -0
  136. fides/ui-build/static/admin/_next/static/chunks/pages/properties/add-property-9ccb295110feee20.js +1 -0
  137. fides/ui-build/static/admin/_next/static/chunks/pages/properties-3a1037a2e036212a.js +1 -0
  138. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-4cdbbb8cd1d8698e.js +1 -0
  139. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-965cc21889b25e44.js +1 -0
  140. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-0e1c381d488a7ada.js +1 -0
  141. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-d0e350d2a2667883.js +1 -0
  142. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-7796fbf458f8f159.js +1 -0
  143. fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-6f866bc799a5f67f.js +1 -0
  144. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domain-records-0b44b2b224077dcd.js +1 -0
  145. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-5d00e1155bd11178.js +1 -0
  146. fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-d2cdbe770683e9df.js +1 -0
  147. fides/ui-build/static/admin/_next/static/chunks/pages/settings/locations-811dadb489f23d7d.js +1 -0
  148. fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-24108f615ff5e1e7.js +1 -0
  149. fides/ui-build/static/admin/_next/static/chunks/pages/settings/regulations-54f142bc3e4c95ba.js +1 -0
  150. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-fef247a87baeb080.js +1 -0
  151. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]-6eb886e7b7e6785b.js +1 -0
  152. fides/ui-build/static/admin/_next/static/chunks/pages/systems-7b71274334c559a4.js +1 -0
  153. fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-18534d2a79a3850b.js +1 -0
  154. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/[id]-75d41fde668b9025.js +1 -0
  155. fides/ui-build/static/admin/_next/static/chunks/pages/user-management-dd43755b687c09a7.js +1 -0
  156. fides/ui-build/static/admin/_next/static/chunks/webpack-0a61b5bd21a41fe6.js +1 -0
  157. fides/ui-build/static/admin/_next/static/css/c693338e3bc8dcc6.css +1 -0
  158. fides/ui-build/static/admin/_next/static/nRQ3pmK_d3F5PJE39rP2h/_buildManifest.js +1 -0
  159. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  160. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  161. fides/ui-build/static/admin/add-systems.html +1 -1
  162. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  163. fides/ui-build/static/admin/consent/configure.html +1 -1
  164. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  165. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  166. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  167. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  168. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  169. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  170. fides/ui-build/static/admin/consent/properties.html +1 -1
  171. fides/ui-build/static/admin/consent/reporting.html +1 -1
  172. fides/ui-build/static/admin/consent.html +1 -1
  173. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  174. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  175. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  176. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  177. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  178. fides/ui-build/static/admin/data-catalog.html +1 -1
  179. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  180. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  181. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  182. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  183. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  184. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  185. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  186. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  187. fides/ui-build/static/admin/datamap.html +1 -1
  188. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  189. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  190. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  191. fides/ui-build/static/admin/dataset/new.html +1 -1
  192. fides/ui-build/static/admin/dataset.html +1 -1
  193. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  194. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  195. fides/ui-build/static/admin/datastore-connection.html +1 -1
  196. fides/ui-build/static/admin/images/connector-logos/salesforce.svg +41 -0
  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/api/service/privacy_request/dsr_package/templates/item.html +0 -37
  246. fides/ui-build/static/admin/_next/static/chunks/1099-667e84655846e78c.js +0 -1
  247. fides/ui-build/static/admin/_next/static/chunks/1100-0b01f500b1eaf60d.js +0 -1
  248. fides/ui-build/static/admin/_next/static/chunks/1817-951f58ddd5d46081.js +0 -1
  249. fides/ui-build/static/admin/_next/static/chunks/1904-964f8eb328dc2715.js +0 -1
  250. fides/ui-build/static/admin/_next/static/chunks/2310-744354001d01f366.js +0 -1
  251. fides/ui-build/static/admin/_next/static/chunks/2921-49af55ad7c631c93.js +0 -1
  252. fides/ui-build/static/admin/_next/static/chunks/3119-e36ae5071c8f27a5.js +0 -1
  253. fides/ui-build/static/admin/_next/static/chunks/3505-113f9c95d34b7aae.js +0 -1
  254. fides/ui-build/static/admin/_next/static/chunks/3513-5c2d412a84a78971.js +0 -1
  255. fides/ui-build/static/admin/_next/static/chunks/3872-45cc725e241211f0.js +0 -1
  256. fides/ui-build/static/admin/_next/static/chunks/3923-b4f701ada3ef0ee0.js +0 -1
  257. fides/ui-build/static/admin/_next/static/chunks/401-7e800aed05537126.js +0 -1
  258. fides/ui-build/static/admin/_next/static/chunks/4060-90a52a9afc655bfc.js +0 -1
  259. fides/ui-build/static/admin/_next/static/chunks/4121-66b0e00d5e7ae817.js +0 -1
  260. fides/ui-build/static/admin/_next/static/chunks/4132-9b1731bfec6ee537.js +0 -1
  261. fides/ui-build/static/admin/_next/static/chunks/4481-7f6710c928bb0cb0.js +0 -1
  262. fides/ui-build/static/admin/_next/static/chunks/5258-2079138c8cc34f6c.js +0 -1
  263. fides/ui-build/static/admin/_next/static/chunks/5404-2694509cf5fa96da.js +0 -1
  264. fides/ui-build/static/admin/_next/static/chunks/5487-2cbd8d2169eb2a65.js +0 -1
  265. fides/ui-build/static/admin/_next/static/chunks/5683-37137111b3e769fb.js +0 -1
  266. fides/ui-build/static/admin/_next/static/chunks/6202-081545c7822d09af.js +0 -1
  267. fides/ui-build/static/admin/_next/static/chunks/6277-459e054b2702c60e.js +0 -1
  268. fides/ui-build/static/admin/_next/static/chunks/641-7e4eef3222cbda70.js +0 -1
  269. fides/ui-build/static/admin/_next/static/chunks/6853-688df0b88fe65fd5.js +0 -1
  270. fides/ui-build/static/admin/_next/static/chunks/69-00cba94689b9e740.js +0 -1
  271. fides/ui-build/static/admin/_next/static/chunks/6954-4e313b4599b8763d.js +0 -1
  272. fides/ui-build/static/admin/_next/static/chunks/7553-08bc3d9f66695111.js +0 -1
  273. fides/ui-build/static/admin/_next/static/chunks/79-fc548561beed136f.js +0 -1
  274. fides/ui-build/static/admin/_next/static/chunks/796-d6586308ed44334b.js +0 -1
  275. fides/ui-build/static/admin/_next/static/chunks/7980-736f9fd1e749ddd2.js +0 -1
  276. fides/ui-build/static/admin/_next/static/chunks/8032-74d94f7bd5b81c89.js +0 -1
  277. fides/ui-build/static/admin/_next/static/chunks/8433-51870336908fb253.js +0 -1
  278. fides/ui-build/static/admin/_next/static/chunks/8499-1fd392d0be9e8ee4.js +0 -1
  279. fides/ui-build/static/admin/_next/static/chunks/8702-d1c8296f9f6afc10.js +0 -1
  280. fides/ui-build/static/admin/_next/static/chunks/9033-fdd87182c15b91e2.js +0 -1
  281. fides/ui-build/static/admin/_next/static/chunks/9187-851756440f79cd75.js +0 -1
  282. fides/ui-build/static/admin/_next/static/chunks/9327-6a53461c9764b16f.js +0 -1
  283. fides/ui-build/static/admin/_next/static/chunks/9494-1ffb888b95289891.js +0 -1
  284. fides/ui-build/static/admin/_next/static/chunks/9676.61cf5f6d6a083175.js +0 -1
  285. fides/ui-build/static/admin/_next/static/chunks/9767-afd674014a1d1152.js +0 -1
  286. fides/ui-build/static/admin/_next/static/chunks/pages/404-ec04f826f3dd79ea.js +0 -1
  287. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/manual-1bec086d567aacff.js +0 -1
  288. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/multiple-f68bf100e4e60e88.js +0 -1
  289. fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-effde5cfe49de55f.js +0 -1
  290. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/add-vendors-ec95ed8cb0712828.js +0 -1
  291. fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-4cc195e15e0c3cc8.js +0 -1
  292. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/[id]-be8972c79fb39705.js +0 -1
  293. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience-ccf96207de3b74ea.js +0 -1
  294. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/[id]-b9823cc008372cee.js +0 -1
  295. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/new-373f5772ab41bc93.js +0 -1
  296. fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-b9beeee1bde5ca79.js +0 -1
  297. fides/ui-build/static/admin/_next/static/chunks/pages/consent/properties-6ab3a5baafebd199.js +0 -1
  298. fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-8562790ae07f17c9.js +0 -1
  299. fides/ui-build/static/admin/_next/static/chunks/pages/consent-42d4d2d6e0253671.js +0 -1
  300. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]-9d1df6d890671b0c.js +0 -1
  301. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-7eb08af333baaa8e.js +0 -1
  302. fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-bb57eed84f59a932.js +0 -1
  303. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-47eb34aef3e31ac6.js +0 -1
  304. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-76cefefc53e84c7f.js +0 -1
  305. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-9d8e84a8b4bf568d.js +0 -1
  306. fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-f208fef5e72dafd6.js +0 -1
  307. fides/ui-build/static/admin/_next/static/chunks/pages/datamap-db45aa864e9dda8a.js +0 -1
  308. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-d5cfdebc74654337.js +0 -1
  309. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-618b89228f83435e.js +0 -1
  310. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-12fc86f15a4c764e.js +0 -1
  311. fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-c23d18a9b56c2e3c.js +0 -1
  312. fides/ui-build/static/admin/_next/static/chunks/pages/dataset-e3b2d8e3980ab093.js +0 -1
  313. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/[id]-6e27257eccf65f01.js +0 -1
  314. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-bbac1f624424282d.js +0 -1
  315. fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-84eb56f5a07bdf4f.js +0 -1
  316. fides/ui-build/static/admin/_next/static/chunks/pages/index-773182b5e35d0045.js +0 -1
  317. fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-eb28c927da5bd653.js +0 -1
  318. fides/ui-build/static/admin/_next/static/chunks/pages/integrations-781808bca01f8048.js +0 -1
  319. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/[id]-b51bee8680d66b20.js +0 -1
  320. fides/ui-build/static/admin/_next/static/chunks/pages/messaging/add-template-1de479533f733fbd.js +0 -1
  321. fides/ui-build/static/admin/_next/static/chunks/pages/messaging-7dc295b3ed3d2224.js +0 -1
  322. fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-f64dac3392f5ded7.js +0 -1
  323. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/AntForm-eb020bfac4bee532.js +0 -1
  324. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikAntFormItem-0bd62e28b539e114.js +0 -1
  325. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikControlled-936877004113c2a6.js +0 -1
  326. fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/FormikField-6416f01524482af9.js +0 -1
  327. fides/ui-build/static/admin/_next/static/chunks/pages/poc/forms-3f4e1313d1f2969b.js +0 -1
  328. fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-1db7a54437db7db0.js +0 -1
  329. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-64236fd0141414fd.js +0 -1
  330. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-8cab04871908cfeb.js +0 -1
  331. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-150d40428245ee0c.js +0 -1
  332. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-b6c876dceb16ad1b.js +0 -1
  333. fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-20cdb2c8a03deae1.js +0 -1
  334. fides/ui-build/static/admin/_next/static/chunks/pages/properties/[id]-54bcc875592d1fb9.js +0 -1
  335. fides/ui-build/static/admin/_next/static/chunks/pages/properties/add-property-644dc669b508a79a.js +0 -1
  336. fides/ui-build/static/admin/_next/static/chunks/pages/properties-9a88220d03e7e02f.js +0 -1
  337. fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-70dc1081df37ea69.js +0 -1
  338. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-3c71b4dbcb6fd6c9.js +0 -1
  339. fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-7cb16e0000dd16c9.js +0 -1
  340. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-a18d8f12ee8dcf5d.js +0 -1
  341. fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-dc220e116ad5c09e.js +0 -1
  342. fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-55ddc5f25b86f28e.js +0 -1
  343. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domain-records-5ca7decded228bc8.js +0 -1
  344. fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-a6fafa1be2834c40.js +0 -1
  345. fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-e633750d2b45ddd6.js +0 -1
  346. fides/ui-build/static/admin/_next/static/chunks/pages/settings/locations-3948686cbd372969.js +0 -1
  347. fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-04ece499c22d23f4.js +0 -1
  348. fides/ui-build/static/admin/_next/static/chunks/pages/settings/regulations-7752305084280cca.js +0 -1
  349. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-9e5f9066be6f218d.js +0 -1
  350. fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]-86de9e6d72098e45.js +0 -1
  351. fides/ui-build/static/admin/_next/static/chunks/pages/systems-cac52e6c3abf6a15.js +0 -1
  352. fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-60d5930b6855679b.js +0 -1
  353. fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/[id]-b0f4c34752d32c73.js +0 -1
  354. fides/ui-build/static/admin/_next/static/chunks/pages/user-management-7dee83dd6d9292aa.js +0 -1
  355. fides/ui-build/static/admin/_next/static/chunks/webpack-8457bad7859c44f0.js +0 -1
  356. fides/ui-build/static/admin/_next/static/css/1fdf5c593349dbc6.css +0 -1
  357. fides/ui-build/static/admin/_next/static/f_8LkSZkhtDM14f8gbC0b/_buildManifest.js +0 -1
  358. {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/WHEEL +0 -0
  359. {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/entry_points.txt +0 -0
  360. {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/licenses/LICENSE +0 -0
  361. {ethyca_fides-2.63.3rc0.dist-info → ethyca_fides-2.64.1b0.dist-info}/top_level.txt +0 -0
  362. /fides/ui-build/static/admin/_next/static/{f_8LkSZkhtDM14f8gbC0b → nRQ3pmK_d3F5PJE39rP2h}/_ssgManifest.js +0 -0
@@ -77,35 +77,99 @@ class RedisSettings(FidesSettings):
77
77
  default="",
78
78
  description="The network address for the read-only Redis cache.",
79
79
  )
80
- read_only_port: int = Field(
81
- default=6379,
82
- description="The port at which the read-only Redis cache will be accessible.",
80
+ # Read-only Redis settings with automatic fallback behavior
81
+ # Field validators will populate these fields with the corresponding writer settings if not provided
82
+ # The order here is important, these must be defined after the writer settings
83
+ read_only_port: int = Field( # type: ignore[assignment]
84
+ default=None,
85
+ description="The port at which the read-only Redis cache will be accessible. If not provided, the `port` setting will be used.",
83
86
  )
84
- read_only_user: str = Field(
85
- default="",
86
- description="The user with which to login to the read-only Redis cache.",
87
+ read_only_user: str = Field( # type: ignore[assignment]
88
+ default=None,
89
+ description="The user with which to login to the read-only Redis cache. If not provided, the `user` setting will be used.",
87
90
  )
88
- read_only_password: str = Field(
89
- default="",
90
- description="The password with which to login to the read-only Redis cache.",
91
+ read_only_password: str = Field( # type: ignore[assignment]
92
+ default=None,
93
+ description="The password with which to login to the read-only Redis cache. If not provided, the `password` setting will be used.",
91
94
  )
92
- read_only_db_index: int = Field(
93
- default=0,
94
- description="The application will use this index in the read-only Redis cache to cache data.",
95
+ read_only_db_index: int = Field( # type: ignore[assignment]
96
+ default=None,
97
+ description="The application will use this index in the read-only Redis cache to cache data. If not provided, the `db_index` setting will be used.",
95
98
  )
96
- read_only_ssl: bool = Field(
97
- default=False,
98
- description="Whether the application's connections to the read-only cache should be encrypted using TLS.",
99
+ read_only_ssl: bool = Field( # type: ignore[assignment]
100
+ default=None,
101
+ description="Whether the application's connections to the read-only cache should be encrypted using TLS. If not provided, the `ssl` setting will be used.",
99
102
  )
100
103
  read_only_ssl_cert_reqs: Optional[str] = Field(
101
- default="required",
102
- description="If using TLS encryption, set this to 'required' if you wish to enforce the read-only Redis cache to provide a certificate. Note that not all cache providers support this without setting ssl_ca_certs (e.g. AWS Elasticache).",
104
+ default=None,
105
+ description="If using TLS encryption, set this to 'required' if you wish to enforce the read-only Redis cache to provide a certificate. Note that not all cache providers support this without setting ssl_ca_certs (e.g. AWS Elasticache). If not provided, the `ssl_cert_reqs` setting will be used.",
103
106
  )
104
- read_only_ssl_ca_certs: str = Field(
105
- default="",
106
- description="If using TLS encryption rooted with a custom Certificate Authority, set this to the path of the CA certificate.",
107
+ read_only_ssl_ca_certs: str = Field( # type: ignore[assignment]
108
+ default=None,
109
+ description="If using TLS encryption rooted with a custom Certificate Authority, set this to the path of the CA certificate. If not provided, the `ssl_ca_certs` setting will be used.",
107
110
  )
108
111
 
112
+ # Field validators for automatic fallback behavior
113
+ @field_validator("read_only_port", mode="before")
114
+ @classmethod
115
+ def resolve_read_only_port(cls, v: Optional[int], info: ValidationInfo) -> int:
116
+ """Resolves the read-only port setting by falling back to the `port` value if no `read_only_port` is specified."""
117
+ if v is None:
118
+ return info.data["port"]
119
+ return v
120
+
121
+ @field_validator("read_only_user", mode="before")
122
+ @classmethod
123
+ def resolve_read_only_user(cls, v: Optional[str], info: ValidationInfo) -> str:
124
+ """Resolves the read-only user setting by falling back to the `user` value if no `read_only_user` is specified."""
125
+ if v is None:
126
+ return info.data["user"]
127
+ return v
128
+
129
+ @field_validator("read_only_password", mode="before")
130
+ @classmethod
131
+ def resolve_read_only_password(cls, v: Optional[str], info: ValidationInfo) -> str:
132
+ """Resolves the read-only password setting by falling back to the `password` value if no `read_only_password` is specified."""
133
+ if v is None:
134
+ return info.data["password"]
135
+ return v
136
+
137
+ @field_validator("read_only_db_index", mode="before")
138
+ @classmethod
139
+ def resolve_read_only_db_index(cls, v: Optional[int], info: ValidationInfo) -> int:
140
+ """Resolves the read-only db_index setting by falling back to the `db_index` value if no `read_only_db_index` is specified."""
141
+ if v is None:
142
+ return info.data["db_index"]
143
+ return v
144
+
145
+ @field_validator("read_only_ssl", mode="before")
146
+ @classmethod
147
+ def resolve_read_only_ssl(cls, v: Optional[bool], info: ValidationInfo) -> bool:
148
+ """Resolves the read-only ssl setting by falling back to the `ssl` value if no `read_only_ssl` is specified."""
149
+ if v is None:
150
+ return info.data["ssl"]
151
+ return v
152
+
153
+ @field_validator("read_only_ssl_cert_reqs", mode="before")
154
+ @classmethod
155
+ def resolve_read_only_ssl_cert_reqs(
156
+ cls, v: Optional[str], info: ValidationInfo
157
+ ) -> Optional[str]:
158
+ """Resolves the read-only ssl_cert_reqs setting by falling back to the `ssl_cert_reqs` value if no `read_only_ssl_cert_reqs` is specified."""
159
+ if v is None:
160
+ return info.data["ssl_cert_reqs"]
161
+ return v
162
+
163
+ @field_validator("read_only_ssl_ca_certs", mode="before")
164
+ @classmethod
165
+ def resolve_read_only_ssl_ca_certs(
166
+ cls, v: Optional[str], info: ValidationInfo
167
+ ) -> str:
168
+ """Resolves the read-only ssl_ca_certs setting by falling back to the `ssl_ca_certs` value if no `read_only_ssl_ca_certs` is specified."""
169
+ if v is None:
170
+ return info.data["ssl_ca_certs"]
171
+ return v
172
+
109
173
  # This relies on other values to get built so must be last
110
174
  connection_url: Optional[str] = Field(
111
175
  default=None,
@@ -130,49 +194,48 @@ class RedisSettings(FidesSettings):
130
194
  # If the whole URL is provided via the config, preference that
131
195
  return v
132
196
 
197
+ # Determine which set of settings to use based on field name
133
198
  is_read_only = info.field_name == "read_only_connection_url"
134
199
 
135
- connection_protocol = "redis"
136
- params_str = ""
137
- use_tls = (
138
- info.data.get("read_only_ssl")
139
- if is_read_only
140
- else info.data.get("ssl", False)
141
- )
142
-
143
- # These vars are intentionally fetched with `or ""` as the default to account
144
- # for the edge case where `None` is explicitly set in `values` by Pydantic because
145
- # it is not overridden by the config file or an env var
200
+ # Extract settings - fallbacks already resolved by field validators for read-only fields
146
201
  user = (
147
- info.data.get("read_only_user", "")
148
- if is_read_only
149
- else info.data.get("user", "")
202
+ info.data["read_only_user"] if is_read_only else info.data.get("user", "")
150
203
  )
151
204
  password = (
152
- info.data.get("read_only_password", "")
205
+ info.data["read_only_password"]
153
206
  if is_read_only
154
207
  else info.data.get("password", "")
155
208
  )
209
+
156
210
  db_index = (
157
- info.data.get("read_only_db_index", "")
211
+ info.data["read_only_db_index"]
158
212
  if is_read_only
159
213
  else info.data.get("db_index", "")
160
214
  )
215
+ use_tls = (
216
+ info.data["read_only_ssl"] if is_read_only else info.data.get("ssl", False)
217
+ )
218
+
219
+ connection_protocol = "redis"
220
+ params_str = ""
221
+
161
222
  if use_tls:
162
223
  # If using TLS update the connection URL format
163
224
  connection_protocol = "rediss"
164
- cert_reqs = (
225
+
226
+ ssl_cert_reqs = (
165
227
  info.data.get("read_only_ssl_cert_reqs", "none")
166
228
  if is_read_only
167
229
  else info.data.get("ssl_cert_reqs", "none")
168
230
  )
169
- params = {"ssl_cert_reqs": quote_plus(cert_reqs)}
170
-
171
231
  ssl_ca_certs = (
172
- info.data.get("read_only_ssl_ca_certs", "")
232
+ info.data["read_only_ssl_ca_certs"]
173
233
  if is_read_only
174
234
  else info.data.get("ssl_ca_certs", "")
175
235
  )
236
+
237
+ # Build SSL parameters
238
+ params = {"ssl_cert_reqs": quote_plus(ssl_cert_reqs or "none")}
176
239
  if ssl_ca_certs:
177
240
  params["ssl_ca_certs"] = quote(ssl_ca_certs, safe="/")
178
241
  params_str = "?" + urlencode(params, quote_via=quote, safe="/")
@@ -183,17 +246,15 @@ class RedisSettings(FidesSettings):
183
246
  if password or user:
184
247
  auth_prefix = f"{quote_plus(user)}:{quote_plus(password)}@"
185
248
 
249
+ # For host, we don't have a fallback - read replica should be a different host
186
250
  host = (
187
251
  info.data.get("read_only_host", "")
188
252
  if is_read_only
189
253
  else info.data.get("host", "")
190
254
  )
191
255
  port = (
192
- info.data.get("read_only_port", "")
193
- if is_read_only
194
- else info.data.get("port", "")
256
+ info.data["read_only_port"] if is_read_only else info.data.get("port", "")
195
257
  )
196
-
197
258
  # Only include database index in URL if it's not the default (0)
198
259
  db_path = f"{db_index}" if db_index != 0 else ""
199
260
 
@@ -0,0 +1,370 @@
1
+ from typing import Any, Optional
2
+
3
+ from loguru import logger
4
+ from sqlalchemy.orm import Query, Session, selectinload
5
+
6
+ from fides.api.models.manual_tasks.manual_task import ManualTask
7
+ from fides.api.models.manual_tasks.manual_task_config import (
8
+ ManualTaskConfig,
9
+ ManualTaskConfigField,
10
+ )
11
+ from fides.api.schemas.manual_tasks.manual_task_config import (
12
+ ManualTaskConfigResponse,
13
+ ManualTaskConfigurationType,
14
+ )
15
+ from fides.service.manual_tasks.utils import validate_fields, with_task_logging
16
+
17
+
18
+ class ManualTaskConfigService:
19
+ def __init__(self, db: Session):
20
+ self.db = db
21
+
22
+ def _create_log_data(
23
+ self, task_id: str, config_id: Optional[str], details: dict[str, Any]
24
+ ) -> dict[str, Any]:
25
+ """Create standard log data structure."""
26
+ return {"task_id": task_id, "config_id": config_id, "details": details}
27
+
28
+ def _get_base_config_query(self) -> Query:
29
+ """Get base config query with field definitions loaded."""
30
+ return self.db.query(ManualTaskConfig).options(
31
+ selectinload(ManualTaskConfig.field_definitions)
32
+ )
33
+
34
+ def _create_config_version(
35
+ self,
36
+ task: ManualTask,
37
+ config_type: str,
38
+ version: int,
39
+ is_current: bool = True,
40
+ ) -> ManualTaskConfig:
41
+ """Create a new config version. This is a helper method that creates a new config
42
+ version and sets it as the current version.
43
+
44
+ Args:
45
+ task: The task to create the config for
46
+ config_type: The type of config to create
47
+ version: The version number of the config
48
+ is_current: Whether the config is the current version
49
+ Returns:
50
+ The new config
51
+ """
52
+ try:
53
+ ManualTaskConfigurationType(config_type)
54
+ except ValueError:
55
+ raise ValueError(f"Invalid config type: {config_type}")
56
+
57
+ # Set all existing versions to non-current
58
+ if is_current:
59
+ self.db.query(ManualTaskConfig).filter(
60
+ ManualTaskConfig.task_id == task.id,
61
+ ManualTaskConfig.config_type == config_type,
62
+ ).update({"is_current": False})
63
+ self.db.flush()
64
+
65
+ return ManualTaskConfig.create(
66
+ db=self.db,
67
+ data={
68
+ "task_id": task.id,
69
+ "config_type": config_type,
70
+ "version": version,
71
+ "is_current": is_current,
72
+ },
73
+ )
74
+
75
+ def _handle_field_updates(
76
+ self,
77
+ config: ManualTaskConfig,
78
+ field_updates: Optional[list[dict[str, Any]]] = None,
79
+ fields_to_remove: Optional[list[str]] = None,
80
+ previous_config: Optional[ManualTaskConfig] = None,
81
+ ) -> set[str]:
82
+ """Handle field updates, removals, and recreation from previous version. This is a helper
83
+ function that:
84
+ - Creates new fields from field_updates
85
+ - Recreates unmodified fields from previous version so they will remain in the config
86
+ - Removes fields that are no longer in the config
87
+
88
+ Args:
89
+ config: The config to update
90
+ field_updates: The fields to update
91
+ fields_to_remove: The fields to remove
92
+ previous_config: The previous config
93
+ Returns:
94
+ The modified keys
95
+ """
96
+ modified_keys = set(fields_to_remove or [])
97
+
98
+ if field_updates:
99
+ validate_fields(field_updates, is_submission=False)
100
+ fields_to_create = [
101
+ {
102
+ "task_id": config.task_id,
103
+ "config_id": config.id,
104
+ "field_key": f["field_key"],
105
+ "field_type": f.get("field_type"),
106
+ "field_metadata": f.get("field_metadata", {}),
107
+ }
108
+ for f in field_updates
109
+ ]
110
+ if fields_to_create:
111
+ self.db.bulk_insert_mappings(ManualTaskConfigField, fields_to_create)
112
+ modified_keys.update(f["field_key"] for f in field_updates)
113
+
114
+ if previous_config:
115
+ # Recreate unmodified fields from previous version
116
+ unmodified = [
117
+ {
118
+ "task_id": config.task_id,
119
+ "config_id": config.id,
120
+ "field_key": f.field_key,
121
+ "field_type": f.field_type,
122
+ "field_metadata": f.field_metadata,
123
+ }
124
+ for f in previous_config.field_definitions
125
+ if f.field_key not in modified_keys
126
+ ]
127
+ if unmodified:
128
+ self.db.bulk_insert_mappings(ManualTaskConfigField, unmodified)
129
+
130
+ self.db.flush()
131
+ return modified_keys
132
+
133
+ def to_response(self, config: ManualTaskConfig) -> ManualTaskConfigResponse:
134
+ """Convert config model to response object."""
135
+ return ManualTaskConfigResponse.model_validate(
136
+ {
137
+ "id": config.id,
138
+ "task_id": config.task_id,
139
+ "config_type": config.config_type,
140
+ "version": config.version,
141
+ "is_current": config.is_current,
142
+ "fields": [
143
+ {
144
+ "field_key": f.field_key,
145
+ "field_type": f.field_type,
146
+ "field_metadata": f.field_metadata,
147
+ }
148
+ for f in config.field_definitions
149
+ ],
150
+ "created_at": config.created_at,
151
+ "updated_at": config.updated_at,
152
+ }
153
+ )
154
+
155
+ def get_current_config(
156
+ self, task: ManualTask, config_type: str
157
+ ) -> ManualTaskConfig:
158
+ """Get current config for task by type."""
159
+ config = (
160
+ self._get_base_config_query()
161
+ .filter(
162
+ ManualTaskConfig.task_id == task.id,
163
+ ManualTaskConfig.config_type == config_type,
164
+ ManualTaskConfig.is_current.is_(True),
165
+ )
166
+ .first()
167
+ )
168
+
169
+ if not config:
170
+ raise ValueError(
171
+ f"No current config found for task {task.id} and type {config_type}"
172
+ )
173
+ return config
174
+
175
+ def list_config_type_versions(
176
+ self, task: ManualTask, config_type: str
177
+ ) -> list[ManualTaskConfig]:
178
+ """List all versions of a config type for a task."""
179
+ return (
180
+ self._get_base_config_query()
181
+ .filter(
182
+ ManualTaskConfig.task_id == task.id,
183
+ ManualTaskConfig.config_type == config_type,
184
+ )
185
+ .order_by(ManualTaskConfig.version.desc())
186
+ .all()
187
+ )
188
+
189
+ def get_config(
190
+ self,
191
+ task: ManualTask,
192
+ config_type: str,
193
+ field_id: str,
194
+ config_id: str,
195
+ field_key: str,
196
+ version: int,
197
+ ) -> Optional[ManualTaskConfig]:
198
+ """Get config by various filters. This is a flexible lookup method that can find configs based on various filters.
199
+
200
+ Args:
201
+ task: The task to get the config for
202
+ config_type: The type of config to get
203
+ field_id: The ID of a field in the config
204
+ config_id: The ID of the config
205
+ field_key: The key of a field in the config
206
+ version: The version number of the config
207
+ Returns:
208
+ The matching config if found, None otherwise
209
+ """
210
+ if not any([task, config_id, field_id, config_type]):
211
+ logger.debug("No filters provided to get_config")
212
+ return None
213
+
214
+ query = self._get_base_config_query()
215
+ if field_id or field_key:
216
+ query = query.join(ManualTaskConfig.field_definitions)
217
+
218
+ filters = [
219
+ f
220
+ for f in [
221
+ task and ManualTaskConfig.task_id == task.id,
222
+ config_id and ManualTaskConfig.id == config_id,
223
+ field_id and ManualTaskConfigField.id == field_id,
224
+ field_key and ManualTaskConfigField.field_key == field_key,
225
+ version and ManualTaskConfig.version == version,
226
+ config_type and ManualTaskConfig.config_type == config_type,
227
+ ]
228
+ if f
229
+ ]
230
+
231
+ return query.filter(*filters).first()
232
+
233
+ @with_task_logging("Creating new configuration version")
234
+ def create_new_version(
235
+ self,
236
+ task: ManualTask,
237
+ config_type: str,
238
+ field_updates: Optional[list[dict[str, Any]]] = None,
239
+ fields_to_remove: Optional[list[str]] = None,
240
+ previous_config: Optional[ManualTaskConfig] = None,
241
+ ) -> tuple[ManualTaskConfig, dict[str, Any]]:
242
+ """Create new version of configuration.
243
+
244
+ Args:
245
+ task: The task to create the config for
246
+ config_type: The type of config to create
247
+ field_updates: The fields to update
248
+ fields_to_remove: The fields to remove
249
+ previous_config: The previous config
250
+
251
+ Returns:
252
+ Tuple containing the new config and log data, the log data is
253
+ captured by the with_task_logging decorator. and the new config is
254
+ returned to the caller.
255
+ """
256
+ new_config = self._create_config_version(
257
+ task, config_type, (previous_config.version + 1 if previous_config else 1)
258
+ )
259
+
260
+ self._handle_field_updates(
261
+ new_config, field_updates, fields_to_remove, previous_config
262
+ )
263
+
264
+ return new_config, self._create_log_data(
265
+ task.id,
266
+ new_config.id,
267
+ {
268
+ "config_type": config_type,
269
+ "version": new_config.version,
270
+ "added_field_keys": [f.get("field_key") for f in (field_updates or [])],
271
+ "removed_field_keys": fields_to_remove or [],
272
+ },
273
+ )
274
+
275
+ @with_task_logging("Adding fields to configuration")
276
+ def add_fields(
277
+ self, task: ManualTask, config_type: str, fields: list[dict[str, Any]]
278
+ ) -> tuple[ManualTaskConfig, dict[str, Any]]:
279
+ """Add fields to configuration.
280
+
281
+ Args:
282
+ task: The task to add the fields to
283
+ config_type: The type of config to add the fields to
284
+ fields: The fields to add
285
+
286
+ Returns:
287
+ Tuple containing the new config and log data, the log data is
288
+ captured by the with_task_logging decorator. and the new config is
289
+ returned to the caller.
290
+ """
291
+ current = self.get_current_config(task, config_type)
292
+ self.create_new_version(task, config_type, fields, previous_config=current)
293
+ new_config = self.get_current_config(task, config_type)
294
+
295
+ return new_config, self._create_log_data(
296
+ task.id,
297
+ current.id,
298
+ {
299
+ "config_type": config_type,
300
+ "previous_version": current.version,
301
+ "added_field_keys": [f.get("field_key") for f in fields],
302
+ "new_config_id": new_config.id,
303
+ "new_config_version": new_config.version,
304
+ },
305
+ )
306
+
307
+ @with_task_logging("Removing fields from configuration")
308
+ def remove_fields(
309
+ self, task: ManualTask, config_type: str, field_keys: list[str]
310
+ ) -> tuple[ManualTaskConfig, dict[str, Any]]:
311
+ """Remove fields from configuration.
312
+
313
+ Args:
314
+ task: The task to remove the fields from
315
+ config_type: The type of config to remove the fields from
316
+ field_keys: The keys of the fields to remove
317
+
318
+ Returns:
319
+ Tuple containing the new config and log data, the log data is
320
+ captured by the with_task_logging decorator. and the new config is
321
+ returned to the caller.
322
+ """
323
+ current = self.get_current_config(task, config_type)
324
+ self.create_new_version(
325
+ task, config_type, fields_to_remove=field_keys, previous_config=current
326
+ )
327
+ new_config = self.get_current_config(task, config_type)
328
+
329
+ return new_config, self._create_log_data(
330
+ task.id,
331
+ current.id,
332
+ {
333
+ "config_type": config_type,
334
+ "version": current.version,
335
+ "deleted_field_keys": field_keys,
336
+ "new_config_id": new_config.id,
337
+ "new_config_version": new_config.version,
338
+ },
339
+ )
340
+
341
+ @with_task_logging("Deleting Manual Task configuration")
342
+ def delete_config(
343
+ self, task: ManualTask, config_id: str
344
+ ) -> tuple[ManualTaskConfig, dict[str, Any]]:
345
+ """Delete config for task.
346
+
347
+ Args:
348
+ task: The task to delete the config for
349
+ config_id: The ID of the config to delete
350
+
351
+ Returns:
352
+ Tuple containing the deleted config and log data, the log data is
353
+ captured by the with_task_logging decorator. and the deleted config is
354
+ returned to the caller.
355
+ """
356
+ config = self.db.query(ManualTaskConfig).filter_by(id=config_id).first()
357
+ if not config:
358
+ raise ValueError(f"Config with ID {config_id} not found")
359
+
360
+ log_data = self._create_log_data(
361
+ task.id,
362
+ None,
363
+ {
364
+ "config_type": config.config_type,
365
+ "version": config.version,
366
+ "deleted_config_id": config_id,
367
+ },
368
+ )
369
+ config.delete(self.db)
370
+ return config, log_data