ethyca-fides 2.68.1b2__py2.py3-none-any.whl → 2.68.1b4__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of ethyca-fides might be problematic. Click here for more details.
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/METADATA +3 -1
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/RECORD +253 -232
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/90502bcda282_update_request_tasks_add_polling_async.py +35 -0
- fides/api/alembic/migrations/versions/b1a2c3d4e5f6_add_location_to_privacy_request.py +26 -0
- fides/api/api/v1/api.py +2 -0
- fides/api/api/v1/endpoints/dsr_package_link.py +167 -0
- fides/api/api/v1/endpoints/privacy_request_endpoints.py +31 -1
- fides/api/api/v1/endpoints/user_endpoints.py +4 -0
- fides/api/common_exceptions.py +12 -3
- fides/api/models/detection_discovery/core.py +6 -0
- fides/api/models/privacy_request/privacy_request.py +1 -0
- fides/api/models/privacy_request/request_task.py +25 -0
- fides/api/models/privacy_request/webhook.py +33 -1
- fides/api/oauth/utils.py +122 -57
- fides/api/schemas/application_config.py +7 -0
- fides/api/schemas/connection_configuration/connection_type_system_map.py +6 -0
- fides/api/schemas/enums/__init__.py +0 -0
- fides/api/schemas/enums/connection_category.py +20 -0
- fides/api/schemas/enums/integration_feature.py +23 -0
- fides/api/schemas/external_https.py +9 -0
- fides/api/schemas/privacy_center_config.py +48 -19
- fides/api/schemas/privacy_request.py +16 -0
- fides/api/schemas/saas/display_info.py +19 -0
- fides/api/schemas/saas/saas_config.py +2 -0
- fides/api/schemas/storage/storage.py +4 -0
- fides/api/service/async_dsr/__init__.py +0 -0
- fides/api/service/async_dsr/async_dsr_service.py +75 -0
- fides/api/service/connectors/saas_connector.py +5 -6
- fides/api/service/privacy_request/dsr_package/dsr_report_builder.py +6 -4
- fides/api/service/privacy_request/request_runner_service.py +41 -4
- fides/api/service/privacy_request/request_service.py +50 -2
- fides/api/service/storage/storage_uploader_service.py +80 -5
- fides/api/service/storage/streaming/__init__.py +42 -0
- fides/api/service/storage/streaming/base_storage_client.py +61 -0
- fides/api/service/storage/streaming/dsr_storage.py +98 -0
- fides/api/service/storage/streaming/retry.py +282 -0
- fides/api/service/storage/streaming/s3/__init__.py +5 -0
- fides/api/service/storage/streaming/s3/s3_storage_client.py +113 -0
- fides/api/service/storage/streaming/s3/streaming_s3.py +196 -0
- fides/api/service/storage/streaming/schemas.py +173 -0
- fides/api/service/storage/streaming/smart_open_client.py +265 -0
- fides/api/service/storage/streaming/smart_open_streaming_storage.py +998 -0
- fides/api/service/storage/streaming/storage_client_factory.py +60 -0
- fides/api/task/graph_task.py +4 -4
- fides/api/task/manual/manual_task_graph_task.py +3 -4
- fides/api/util/connection_type.py +20 -0
- fides/api/util/text.py +51 -0
- fides/common/api/v1/urn_registry.py +3 -0
- fides/config/execution_settings.py +4 -0
- fides/service/privacy_request/privacy_request_service.py +84 -9
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/LRCvfOqg1kP5kGnkD84G4/_buildManifest.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1099-b973dfdfc5c3de90.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1345-b60d1f3442379c73.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{1817-c90365325f8a3d75.js → 1817-74692de5d760a664.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{1975.e5cc7a1ccd477671.js → 1975.78e719130cfe3fd6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{2921-46f9465c2852a46b.js → 2921-2d9261e8e2e127c0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/3620-ebd89f91b82661e8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3729-ccf90cdaae158f39.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3847-2759bf1f47a1d29e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3855-4174a4d4c205d6e8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3872-660aba76572c811b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3923-a33633feba5e655e.js → 3923-c6cdc2e5278ae9a7.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{401-741bb31b586b7c96.js → 401-8bc2c6c84172c096.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{4121-94354b50a41f8497.js → 4121-9a4ebceff9accb7f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/431-86ad2beeb93c95c9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4608-4d31340b0d0157c1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4786-aaef673b30c19e2e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4808-a654c7f7a1ca62c8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4844-cd7e1d0c7bb94094.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5258-bc4a25d43e4aa07d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5487-37c78c4799ba5223.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/549-2213dc1c34143cda.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{6084-02abe12327fc3dbc.js → 6084-55cc66e7c94f0686.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6853-270261ef5537a106.js → 6853-313ce974d33432fb.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/6954-021bd06d0ab59c3c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7476-2fc286c2a9125eb8.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7630-b9a41262a69edf5e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/768-034e121688a3bbdd.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{787-5ba991cad1f7664a.js → 787-8df7118742e84908.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/79-d2ace89108ead8ae.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/796-2de6dac5f311d54a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/8002-cfdc6574bd841892.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9046-c44e41da49338c6c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9676.b7d5d1d90b9da224.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{9826-8c81c97a72510fcf.js → 9826-d9addbd5ac990fa4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9951-6ee5c0a23951a07f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{404-9174cdb70126c2c5.js → 404-9644eb282f2dcd71.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-2c10f6b217b7978b.js → _app-284cba7174fa1f16.js} +136 -135
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-621416493c89ef01.js → manual-42b7fd34712f49bd.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-0b9908c3e1dfe49e.js → multiple-4f164eab0960bbe0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-985d3c9179e69d7f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-5bb1b31ae8752250.js → add-vendors-61090926e5f98a5d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-17ffe691b91cee2e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-4e4d9426743b5cb4.js → [id]-95c13bca5c1e575e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-d72460348fadcab8.js → privacy-experience-609399510a60beb9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-3e7ddc252da00c98.js → [id]-d7d8f228ac74b26e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-35a7c305beee9428.js → new-821c0f82d5a2b7d4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-8365782543cf6ab9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-ab96939421639153.js → properties-40a7aa65f4d13cf9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-e4bacfc5c2ed2324.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{consent-13240e3ca77acfeb.js → consent-70c5c6aa5389d99f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-aad6047a4604b945.js → [resourceUrn]-adc500a03e239857.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-bd37b407c80c6986.js → [projectUrn]-3207f62e5012611b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-7b42dee0fb696658.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-b6b98cea25dd94fa.js → [resourceUrn]-c8b3d090e4ba60d3.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-31a45ea2ca2a7f04.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-6172c2eb539319fd.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-945d354ff057fb03.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-d9795e00f39cf4e9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-657833fd8528280f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-31e6c54794a9883e.js → [resourceUrn]-22eec362dfbb1d2a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-2822a423a7ad0550.js → detection-4decce5ef996e563.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-f98dd251babb7e28.js → [resourceUrn]-01acdd1ad492fd89.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-56eb4c014f0d96a3.js → discovery-85fdbf4cde60d910.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-8f88dc31c5144ea8.js → datamap-3a4b89fb21d14753.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-cb8d303f56091bd5.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-401c8be76d9daec7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-97e2d375b21cfe43.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-40ef544ca1f2c9b9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-e3c763f8e71f8e24.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-67a7fe58b96ea739.js → [id]-152e5d15705ec072.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-651b10cae0e99a05.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-03c54bc9fb18d2b0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{index-876bfd7210040cec.js → index-3d19b9ffa15a928a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-4b0bb4ccfb237d41.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-78d4e0c14654148b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-6e796c3fe632280b.js → [id]-72cb360a6d14e701.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-fa0f3841c5bdfdeb.js → add-template-0ed67cf774d5cbf5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging-b06a2204e2a5b667.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-7050899b3f792129.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{AntForm-11503454a62d8d7b.js → AntForm-7c3466f4d5797e55.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikAntFormItem-a504941807bdb7f1.js → FormikAntFormItem-8de252f25871bab9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikControlled-0119403c8ff97f83.js → FormikControlled-cd6de0da47f980cf.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikField-94f6d57d6c94ddf7.js → FormikField-7c238a881fe30e28.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/{forms-ed1a3ae09d72df89.js → forms-d4f3e8f67f76f146.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-c9220e20c1d93758.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-b9d6886a3f157120.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-9c1fd7867b2d80d7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-fc959ed21dbce38c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-44a4a638dcb2722a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-1433c9f9501a884f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-41976b28503623cd.js → [id]-16e0b42cb342aa5f.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-cb438d8f5ec6007a.js → add-property-ebd114a86b809391.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{properties-b6db7036993709b3.js → properties-901be5fa4a48f48c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-da9ced1e20681154.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-0174554c0ac5958f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-6f45ddbf675e66d2.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-275c49e6089c5c9f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-1a8d05e19f06d857.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-49d86b9ca4523ca6.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-386368bf7cb31771.js → domain-records-f71b4b95d91db926.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-a595cad18cf04673.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-6f7f9751689b042c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-b41fb5ad277088ab.js → locations-e2c88d7f779fe604.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-c65acd2b7ab04753.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-a94dfeea43fbca7d.js → regulations-c1c699eeb40a9dc0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-a274e2191b87e315.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-18b316e2dad73731.js → [id]-4a48b4f996a64957.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-30debc87925634d9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-ca625b1296a029f0.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-3237881945acc0ee.js → [id]-7a3180b235eb8846.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-a3a50d9d79066935.js → user-management-5e2d0acf575252ca.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{webpack-69658aeaf6155d89.js → webpack-4502d4d67006b48f.js} +1 -1
- fides/ui-build/static/admin/_next/static/css/43d0c0fc207767eb.css +1 -0
- fides/ui-build/static/admin/add-systems/manual.html +1 -1
- fides/ui-build/static/admin/add-systems/multiple.html +1 -1
- fides/ui-build/static/admin/add-systems.html +1 -1
- fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
- fides/ui-build/static/admin/consent/configure.html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
- fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
- fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
- fides/ui-build/static/admin/consent/properties.html +1 -1
- fides/ui-build/static/admin/consent/reporting.html +1 -1
- fides/ui-build/static/admin/consent.html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
- fides/ui-build/static/admin/data-catalog.html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
- fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
- fides/ui-build/static/admin/data-discovery/activity.html +1 -1
- fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-discovery/detection.html +1 -1
- fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
- fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
- fides/ui-build/static/admin/datamap.html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
- fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
- fides/ui-build/static/admin/dataset/new.html +1 -1
- fides/ui-build/static/admin/dataset.html +1 -1
- fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
- fides/ui-build/static/admin/datastore-connection/new.html +1 -1
- fides/ui-build/static/admin/datastore-connection.html +1 -1
- fides/ui-build/static/admin/index.html +1 -1
- fides/ui-build/static/admin/integrations/[id].html +1 -1
- fides/ui-build/static/admin/integrations.html +1 -1
- fides/ui-build/static/admin/lib/fides-preview.js +1 -1
- fides/ui-build/static/admin/lib/fides-tcf.js +2 -2
- fides/ui-build/static/admin/login/[provider].html +1 -1
- fides/ui-build/static/admin/login.html +1 -1
- fides/ui-build/static/admin/messaging/[id].html +1 -1
- fides/ui-build/static/admin/messaging/add-template.html +1 -1
- fides/ui-build/static/admin/messaging.html +1 -1
- fides/ui-build/static/admin/poc/ant-components.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
- fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
- fides/ui-build/static/admin/poc/forms.html +1 -1
- fides/ui-build/static/admin/poc/table-migration.html +1 -1
- fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
- fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
- fides/ui-build/static/admin/privacy-requests.html +1 -1
- fides/ui-build/static/admin/properties/[id].html +1 -1
- fides/ui-build/static/admin/properties/add-property.html +1 -1
- fides/ui-build/static/admin/properties.html +1 -1
- fides/ui-build/static/admin/reporting/datamap.html +1 -1
- fides/ui-build/static/admin/settings/about/alpha.html +1 -1
- fides/ui-build/static/admin/settings/about.html +1 -1
- fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
- fides/ui-build/static/admin/settings/consent.html +1 -1
- fides/ui-build/static/admin/settings/custom-fields.html +1 -1
- fides/ui-build/static/admin/settings/domain-records.html +1 -1
- fides/ui-build/static/admin/settings/domains.html +1 -1
- fides/ui-build/static/admin/settings/email-templates.html +1 -1
- fides/ui-build/static/admin/settings/locations.html +1 -1
- fides/ui-build/static/admin/settings/organization.html +1 -1
- fides/ui-build/static/admin/settings/regulations.html +1 -1
- fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
- fides/ui-build/static/admin/systems/configure/[id].html +1 -1
- fides/ui-build/static/admin/systems.html +1 -1
- fides/ui-build/static/admin/taxonomy.html +1 -1
- fides/ui-build/static/admin/user-management/new.html +1 -1
- fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
- fides/ui-build/static/admin/user-management.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/203-0c6cadcda98bdd33.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3450-9314e1b15df8a8da.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3855-4267fd8193e7f525.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3872-ac5feefd40b61ae3.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/409-5bc4369b80a8c11d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4230-1ebc8c0ab293a077.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/431-a34d7ceff17c2169.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4608-557fb24665b2e4bf.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5309-ffdec884eec79d29.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5574-831167a8da90e2e6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6662-499c189f932a35aa.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6780-7d28e030f6516e5d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6882-7cc1d14e27a80c10.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6954-7784e8d5ad6b8110.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7476-4de465016d3433b4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7630-2a5c57787632693d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7725-c79513b04113112b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/79-98cfab20bb831137.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/796-0b768155bf20505f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/8735-f84afcc50885883c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9046-97a972cc8a8ed24d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9226-318dadf1c050ecda.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9676.9e6828b42ef05e06.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9951-4df2b67e0def5500.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-18e96ce81dab51a4.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-54d7c7310763c66d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-6bc3b73a21576869.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-fe3d6887fecf0f86.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-e4770acf7044e2f5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-0db635c3483c9da8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-0c0e0a7798345541.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-3c56e5fe072a44c6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-58827eb86516931f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-6a90131dcecd694c.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-145fe9e4cfcb231d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-8a1e5d140785c1e9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-227b5db4b472a6a7.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-8401f17fe5d9a1dc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-7d77b3ad069be268.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-90a8df230cb89877.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-cfb25b02abb8da71.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-4e286a1e501a0c73.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-3fdc55d4c129e618.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging-8f9c006b6166f002.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-6ba7ae4f26c06cb0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-e8db3ad525e7ddbd.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-c14dd24592369467.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-100d7d03930629a8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-6f8d1b3ec83cfcf0.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-3ce15577435d47cb.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-709bcb0bc6a5382d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-4bc3e281409265cc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-1ea40fcd6b4268bf.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-65c7600fadc6e55a.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-33dab986141b3663.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-1195042727c399ed.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-71b98858ecb4e097.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-cf427e04f862b5d2.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-eabeeec5bf2773c6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-ee56698ae3a6a78b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-0e2e98cc38ee5499.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-c32589c86081b750.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-a8f09bf8f3204ca7.js +0 -1
- fides/ui-build/static/admin/_next/static/css/a72179b1754aadd3.css +0 -1
- fides/ui-build/static/admin/_next/static/qvk5eMANVfwYkdURE7fgG/_buildManifest.js +0 -1
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b4.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{qvk5eMANVfwYkdURE7fgG → LRCvfOqg1kP5kGnkD84G4}/_ssgManifest.js +0 -0
|
@@ -5,13 +5,12 @@ import zipfile
|
|
|
5
5
|
from collections import defaultdict
|
|
6
6
|
from io import BytesIO
|
|
7
7
|
from pathlib import Path
|
|
8
|
-
from typing import Any, Optional
|
|
8
|
+
from typing import TYPE_CHECKING, Any, Optional
|
|
9
9
|
|
|
10
10
|
import jinja2
|
|
11
11
|
from jinja2 import Environment, FileSystemLoader
|
|
12
12
|
from loguru import logger
|
|
13
13
|
|
|
14
|
-
from fides.api.models.privacy_request import PrivacyRequest
|
|
15
14
|
from fides.api.schemas.policy import ActionType
|
|
16
15
|
from fides.api.util.storage_util import StorageJSONEncoder, format_size
|
|
17
16
|
|
|
@@ -21,6 +20,9 @@ TEXT_COLOR = "#4A5568"
|
|
|
21
20
|
HEADER_COLOR = "#FAFAFA"
|
|
22
21
|
BORDER_COLOR = "#E2E8F0"
|
|
23
22
|
|
|
23
|
+
if TYPE_CHECKING:
|
|
24
|
+
from fides.api.models.privacy_request import PrivacyRequest # pragma: no cover
|
|
25
|
+
|
|
24
26
|
|
|
25
27
|
# pylint: disable=too-many-instance-attributes
|
|
26
28
|
class DsrReportBuilder:
|
|
@@ -42,7 +44,7 @@ class DsrReportBuilder:
|
|
|
42
44
|
|
|
43
45
|
def __init__(
|
|
44
46
|
self,
|
|
45
|
-
privacy_request: PrivacyRequest,
|
|
47
|
+
privacy_request: "PrivacyRequest",
|
|
46
48
|
dsr_data: dict[str, Any],
|
|
47
49
|
):
|
|
48
50
|
"""
|
|
@@ -387,7 +389,7 @@ class DsrReportBuilder:
|
|
|
387
389
|
return self.baos
|
|
388
390
|
|
|
389
391
|
|
|
390
|
-
def _map_privacy_request(privacy_request: PrivacyRequest) -> dict[str, Any]:
|
|
392
|
+
def _map_privacy_request(privacy_request: "PrivacyRequest") -> dict[str, Any]:
|
|
391
393
|
"""Creates a map with a subset of values from the privacy request"""
|
|
392
394
|
request_data: dict[str, Any] = {}
|
|
393
395
|
request_data["id"] = privacy_request.id
|
|
@@ -41,6 +41,9 @@ from fides.api.models.privacy_request import (
|
|
|
41
41
|
ProvidedIdentityType,
|
|
42
42
|
can_run_checkpoint,
|
|
43
43
|
)
|
|
44
|
+
from fides.api.models.privacy_request.webhook import (
|
|
45
|
+
generate_privacy_request_download_token,
|
|
46
|
+
)
|
|
44
47
|
from fides.api.schemas.base_class import FidesSchema
|
|
45
48
|
from fides.api.schemas.messaging.messaging import (
|
|
46
49
|
AccessRequestCompleteBodyParams,
|
|
@@ -49,6 +52,7 @@ from fides.api.schemas.messaging.messaging import (
|
|
|
49
52
|
from fides.api.schemas.policy import ActionType, CurrentStep
|
|
50
53
|
from fides.api.schemas.privacy_request import PrivacyRequestStatus
|
|
51
54
|
from fides.api.schemas.redis_cache import Identity
|
|
55
|
+
from fides.api.schemas.storage.storage import StorageType
|
|
52
56
|
from fides.api.service.connectors import FidesConnector, get_connector
|
|
53
57
|
from fides.api.service.connectors.consent_email_connector import (
|
|
54
58
|
CONSENT_EMAIL_CONNECTOR_TYPES,
|
|
@@ -82,6 +86,7 @@ from fides.api.util.logger import Pii, _log_exception, _log_warning
|
|
|
82
86
|
from fides.api.util.logger_context_utils import LoggerContextKeys, log_context
|
|
83
87
|
from fides.api.util.memory_watchdog import memory_limiter
|
|
84
88
|
from fides.common.api.v1.urn_registry import (
|
|
89
|
+
PRIVACY_CENTER_DSR_PACKAGE,
|
|
85
90
|
PRIVACY_REQUEST_TRANSFER_TO_PARENT,
|
|
86
91
|
V1_URL_PREFIX,
|
|
87
92
|
)
|
|
@@ -740,14 +745,17 @@ def run_privacy_request(
|
|
|
740
745
|
else MessagingActionType.PRIVACY_REQUEST_COMPLETE_DELETION
|
|
741
746
|
)
|
|
742
747
|
|
|
743
|
-
|
|
748
|
+
message_send_result = message_send_enabled(
|
|
744
749
|
session,
|
|
745
750
|
privacy_request.property_id,
|
|
746
751
|
action_type,
|
|
747
752
|
legacy_request_completion_enabled,
|
|
748
|
-
)
|
|
753
|
+
)
|
|
754
|
+
has_consent_rules = policy.get_rules_for_action(
|
|
749
755
|
action_type=ActionType.consent
|
|
750
|
-
)
|
|
756
|
+
)
|
|
757
|
+
|
|
758
|
+
if message_send_result and not has_consent_rules:
|
|
751
759
|
if not access_result_urls:
|
|
752
760
|
# For DSR 3.0, if the request had both access and erasure rules, this needs to be fetched
|
|
753
761
|
# from the database because the Privacy Request would have exited
|
|
@@ -763,6 +771,7 @@ def run_privacy_request(
|
|
|
763
771
|
access_result_urls,
|
|
764
772
|
identity_data,
|
|
765
773
|
privacy_request.property_id,
|
|
774
|
+
privacy_request.id,
|
|
766
775
|
)
|
|
767
776
|
except (
|
|
768
777
|
IdentityNotFoundException,
|
|
@@ -780,6 +789,7 @@ def initiate_privacy_request_completion_email(
|
|
|
780
789
|
access_result_urls: list[str],
|
|
781
790
|
identity_data: dict[str, Any],
|
|
782
791
|
property_id: Optional[str],
|
|
792
|
+
privacy_request_id: str,
|
|
783
793
|
) -> None:
|
|
784
794
|
"""
|
|
785
795
|
:param session: SQLAlchemy Session
|
|
@@ -787,6 +797,7 @@ def initiate_privacy_request_completion_email(
|
|
|
787
797
|
:param access_result_urls: list of urls generated by access request upload
|
|
788
798
|
:param identity_data: Dict of identity data
|
|
789
799
|
:param property_id: Property id associated with the privacy request
|
|
800
|
+
:param privacy_request_id: ID of the privacy request for generating DSR package links
|
|
790
801
|
"""
|
|
791
802
|
config_proxy = ConfigProxy(session)
|
|
792
803
|
if not (
|
|
@@ -801,6 +812,32 @@ def initiate_privacy_request_completion_email(
|
|
|
801
812
|
phone_number=identity_data.get(ProvidedIdentityType.phone_number.value),
|
|
802
813
|
)
|
|
803
814
|
if policy.get_rules_for_action(action_type=ActionType.access):
|
|
815
|
+
# Check if any rule has enable_access_package_redirect=True and enable_streaming=True in storage config
|
|
816
|
+
# This can be extended to other storage types and non streaming access results in the future
|
|
817
|
+
use_dsr_package_links = False
|
|
818
|
+
for rule in policy.get_rules_for_action(action_type=ActionType.access):
|
|
819
|
+
storage_destination = rule.get_storage_destination(session)
|
|
820
|
+
if (
|
|
821
|
+
storage_destination.type == StorageType.s3
|
|
822
|
+
and storage_destination.details.get("enable_access_package_redirect")
|
|
823
|
+
and storage_destination.details.get("enable_streaming")
|
|
824
|
+
):
|
|
825
|
+
use_dsr_package_links = True
|
|
826
|
+
break
|
|
827
|
+
|
|
828
|
+
# Generate appropriate URLs based on streaming configuration
|
|
829
|
+
if use_dsr_package_links and config_proxy.privacy_center.url:
|
|
830
|
+
# Use DSR package links instead of direct storage URLs
|
|
831
|
+
# Generate the download token for security
|
|
832
|
+
download_token = generate_privacy_request_download_token(privacy_request_id)
|
|
833
|
+
|
|
834
|
+
# Generate DSR package URLs for the messaging template system
|
|
835
|
+
dsr_package_url = f"{config_proxy.privacy_center.url}/api{PRIVACY_CENTER_DSR_PACKAGE.format(privacy_request_id=privacy_request_id)}?token={download_token}"
|
|
836
|
+
download_links = [dsr_package_url]
|
|
837
|
+
else:
|
|
838
|
+
# Use original direct storage URLs
|
|
839
|
+
download_links = access_result_urls
|
|
840
|
+
|
|
804
841
|
# synchronous for now since failure to send complete emails is fatal to request
|
|
805
842
|
dispatch_message(
|
|
806
843
|
db=session,
|
|
@@ -808,7 +845,7 @@ def initiate_privacy_request_completion_email(
|
|
|
808
845
|
to_identity=to_identity,
|
|
809
846
|
service_type=config_proxy.notifications.notification_service_type,
|
|
810
847
|
message_body_params=AccessRequestCompleteBodyParams(
|
|
811
|
-
download_links=
|
|
848
|
+
download_links=download_links,
|
|
812
849
|
subject_request_download_time_in_days=CONFIG.security.subject_request_download_link_ttl_seconds
|
|
813
850
|
/ 86400,
|
|
814
851
|
),
|
|
@@ -11,12 +11,13 @@ from sqlalchemy import text
|
|
|
11
11
|
from sqlalchemy.orm import Session
|
|
12
12
|
from sqlalchemy.sql.elements import TextClause
|
|
13
13
|
|
|
14
|
-
from fides.api.common_exceptions import PrivacyRequestNotFound
|
|
14
|
+
from fides.api.common_exceptions import PrivacyRequestError, PrivacyRequestNotFound
|
|
15
15
|
from fides.api.models.privacy_request import (
|
|
16
16
|
EXITED_EXECUTION_LOG_STATUSES,
|
|
17
17
|
PrivacyRequest,
|
|
18
18
|
RequestTask,
|
|
19
19
|
)
|
|
20
|
+
from fides.api.models.privacy_request.request_task import AsyncTaskType
|
|
20
21
|
from fides.api.models.worker_task import ExecutionLogStatus
|
|
21
22
|
from fides.api.schemas.drp_privacy_request import DrpPrivacyRequestCreate
|
|
22
23
|
from fides.api.schemas.policy import ActionType
|
|
@@ -43,6 +44,7 @@ from fides.config import CONFIG
|
|
|
43
44
|
PRIVACY_REQUEST_STATUS_CHANGE_POLL = "privacy_request_status_change_poll"
|
|
44
45
|
DSR_DATA_REMOVAL = "dsr_data_removal"
|
|
45
46
|
INTERRUPTED_TASK_REQUEUE_POLL = "interrupted_task_requeue_poll"
|
|
47
|
+
ASYNC_TASKS_STATUS_POLLING = "async_tasks_status_polling"
|
|
46
48
|
|
|
47
49
|
|
|
48
50
|
def build_required_privacy_request_kwargs(
|
|
@@ -357,6 +359,27 @@ def initiate_interrupted_task_requeue_poll() -> None:
|
|
|
357
359
|
)
|
|
358
360
|
|
|
359
361
|
|
|
362
|
+
def initiate_async_tasks_status_polling() -> None:
|
|
363
|
+
"""Initiates scheduler to check for and requeue pending polling async tasks"""
|
|
364
|
+
if CONFIG.test_mode:
|
|
365
|
+
return
|
|
366
|
+
|
|
367
|
+
assert (
|
|
368
|
+
scheduler.running
|
|
369
|
+
), "Scheduler is not running! Cannot add async tasks status polling job."
|
|
370
|
+
|
|
371
|
+
logger.info("Initiating scheduler for async tasks status polling")
|
|
372
|
+
scheduler.add_job(
|
|
373
|
+
func=poll_async_tasks_status,
|
|
374
|
+
trigger="interval",
|
|
375
|
+
kwargs={},
|
|
376
|
+
id=ASYNC_TASKS_STATUS_POLLING,
|
|
377
|
+
coalesce=True,
|
|
378
|
+
replace_existing=True,
|
|
379
|
+
seconds=CONFIG.execution.async_tasks_status_polling_interval_seconds,
|
|
380
|
+
)
|
|
381
|
+
|
|
382
|
+
|
|
360
383
|
def get_cached_task_id(entity_id: str) -> Optional[str]:
|
|
361
384
|
"""Gets the cached task ID for a privacy request or request task by ID.
|
|
362
385
|
|
|
@@ -465,7 +488,6 @@ def _handle_privacy_request_requeue(
|
|
|
465
488
|
)
|
|
466
489
|
|
|
467
490
|
from fides.service.privacy_request.privacy_request_service import ( # pylint: disable=cyclic-import
|
|
468
|
-
PrivacyRequestError,
|
|
469
491
|
_requeue_privacy_request,
|
|
470
492
|
)
|
|
471
493
|
|
|
@@ -662,3 +684,29 @@ def requeue_interrupted_tasks(self: DatabaseTask) -> None:
|
|
|
662
684
|
# Requeue the privacy request if needed
|
|
663
685
|
if should_requeue:
|
|
664
686
|
_handle_privacy_request_requeue(db, privacy_request)
|
|
687
|
+
|
|
688
|
+
|
|
689
|
+
@celery_app.task(base=DatabaseTask, bind=True)
|
|
690
|
+
def poll_async_tasks_status(self: DatabaseTask) -> None:
|
|
691
|
+
"""
|
|
692
|
+
Poll the status of async tasks that are awaiting processing.
|
|
693
|
+
"""
|
|
694
|
+
|
|
695
|
+
with self.get_new_session() as db:
|
|
696
|
+
logger.debug("Polling for async tasks status")
|
|
697
|
+
|
|
698
|
+
# Get all tasks that are awaiting processing and are from polling async tasks
|
|
699
|
+
async_tasks = (
|
|
700
|
+
db.query(RequestTask)
|
|
701
|
+
.filter(RequestTask.status == ExecutionLogStatus.awaiting_processing)
|
|
702
|
+
.filter(RequestTask.async_type == AsyncTaskType.polling)
|
|
703
|
+
.all()
|
|
704
|
+
)
|
|
705
|
+
if async_tasks:
|
|
706
|
+
logger.debug(f"Found {len(async_tasks)} async tasks to poll")
|
|
707
|
+
from fides.api.service.async_dsr.async_dsr_service import ( # pylint: disable=cyclic-import
|
|
708
|
+
requeue_polling_request,
|
|
709
|
+
)
|
|
710
|
+
|
|
711
|
+
for async_task in async_tasks:
|
|
712
|
+
requeue_polling_request(db, async_task)
|
|
@@ -14,6 +14,7 @@ from fides.api.schemas.storage.storage import (
|
|
|
14
14
|
StorageDetails,
|
|
15
15
|
StorageType,
|
|
16
16
|
)
|
|
17
|
+
from fides.api.service.storage.streaming.s3.streaming_s3 import upload_to_s3_streaming
|
|
17
18
|
from fides.api.tasks.storage import upload_to_gcs, upload_to_local, upload_to_s3
|
|
18
19
|
|
|
19
20
|
|
|
@@ -33,6 +34,8 @@ def upload(
|
|
|
33
34
|
:param storage_key: Key representing where to upload data
|
|
34
35
|
:return str representing location of upload (url or simply a description of where to find the data)
|
|
35
36
|
"""
|
|
37
|
+
logger.debug("upload called with storage_key: {}", storage_key)
|
|
38
|
+
|
|
36
39
|
config: Optional[StorageConfig] = StorageConfig.get_by(
|
|
37
40
|
db=db, field="key", value=storage_key
|
|
38
41
|
)
|
|
@@ -40,16 +43,41 @@ def upload(
|
|
|
40
43
|
if config is None:
|
|
41
44
|
logger.warning("Storage type not found: {}", storage_key)
|
|
42
45
|
raise StorageUploadError(f"Storage type not found: {storage_key}")
|
|
46
|
+
|
|
47
|
+
logger.debug(
|
|
48
|
+
"Retrieved storage config: key={}, type={}, has_secrets={}",
|
|
49
|
+
config.key,
|
|
50
|
+
config.type,
|
|
51
|
+
config.secrets is not None,
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
if config.secrets:
|
|
55
|
+
logger.debug("Storage config secrets type: {}", type(config.secrets))
|
|
56
|
+
if isinstance(config.secrets, dict):
|
|
57
|
+
logger.debug("Storage config secrets keys: {}", list(config.secrets.keys()))
|
|
58
|
+
else:
|
|
59
|
+
logger.debug("Storage config secrets is not a dict: {}", config.secrets)
|
|
60
|
+
else:
|
|
61
|
+
logger.warning("Storage config has no secrets!")
|
|
62
|
+
|
|
43
63
|
uploader: Any = _get_uploader_from_config_type(config.type) # type: ignore
|
|
64
|
+
logger.debug(
|
|
65
|
+
"Using uploader: {}",
|
|
66
|
+
uploader.__name__ if hasattr(uploader, "__name__") else type(uploader),
|
|
67
|
+
)
|
|
68
|
+
|
|
44
69
|
return uploader(db, config, data, privacy_request)
|
|
45
70
|
|
|
46
71
|
|
|
47
|
-
def get_extension(resp_format: ResponseFormat) -> str:
|
|
72
|
+
def get_extension(resp_format: ResponseFormat, enable_streaming: bool = False) -> str:
|
|
48
73
|
"""
|
|
49
74
|
Determine file extension for various response formats.
|
|
50
75
|
|
|
51
76
|
CSV's and HTML reports are zipped together before uploading to s3.
|
|
52
77
|
"""
|
|
78
|
+
if enable_streaming:
|
|
79
|
+
return "zip"
|
|
80
|
+
|
|
53
81
|
if resp_format == ResponseFormat.csv:
|
|
54
82
|
return "zip"
|
|
55
83
|
|
|
@@ -62,7 +90,9 @@ def get_extension(resp_format: ResponseFormat) -> str:
|
|
|
62
90
|
raise NotImplementedError(f"No extension defined for {resp_format}")
|
|
63
91
|
|
|
64
92
|
|
|
65
|
-
def _construct_file_key(
|
|
93
|
+
def _construct_file_key(
|
|
94
|
+
request_id: str, config: StorageConfig, enable_streaming: bool = False
|
|
95
|
+
) -> str:
|
|
66
96
|
"""Constructs file key based on desired naming convention and request id, e.g. 23847234.json"""
|
|
67
97
|
naming = config.details.get(
|
|
68
98
|
StorageDetails.NAMING.value, FileNaming.request_id.value
|
|
@@ -70,7 +100,7 @@ def _construct_file_key(request_id: str, config: StorageConfig) -> str:
|
|
|
70
100
|
if naming != FileNaming.request_id.value:
|
|
71
101
|
raise ValueError(f"File naming of {naming} not supported")
|
|
72
102
|
|
|
73
|
-
return f"{request_id}.{get_extension(config.format)}" # type: ignore
|
|
103
|
+
return f"{request_id}.{get_extension(config.format, enable_streaming)}" # type: ignore
|
|
74
104
|
|
|
75
105
|
|
|
76
106
|
def _get_uploader_from_config_type(storage_type: StorageType) -> Any:
|
|
@@ -88,13 +118,58 @@ def _s3_uploader(
|
|
|
88
118
|
data: Dict,
|
|
89
119
|
privacy_request: PrivacyRequest,
|
|
90
120
|
) -> str:
|
|
91
|
-
"""
|
|
92
|
-
|
|
121
|
+
"""
|
|
122
|
+
Constructs necessary info needed for s3 before calling upload.
|
|
123
|
+
If `enable_streaming` is configured in the storage config, we use a streaming approach for better memory efficiency.
|
|
124
|
+
Otherwise we fall back to the traditional upload method.
|
|
125
|
+
"""
|
|
126
|
+
logger.debug(
|
|
127
|
+
"_s3_uploader called with config: key={}, type={}, has_secrets={}",
|
|
128
|
+
config.key,
|
|
129
|
+
config.type,
|
|
130
|
+
config.secrets is not None,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
if config.secrets:
|
|
134
|
+
logger.debug(
|
|
135
|
+
"Config secrets keys: {}",
|
|
136
|
+
(
|
|
137
|
+
list(config.secrets.keys())
|
|
138
|
+
if isinstance(config.secrets, dict)
|
|
139
|
+
else "Not a dict"
|
|
140
|
+
),
|
|
141
|
+
)
|
|
142
|
+
logger.debug("Config secrets type: {}", type(config.secrets))
|
|
143
|
+
else:
|
|
144
|
+
logger.warning("Config secrets is None or empty!")
|
|
145
|
+
|
|
146
|
+
enable_streaming = config.details.get(StorageDetails.ENABLE_STREAMING.value, False)
|
|
147
|
+
file_key: str = _construct_file_key(privacy_request.id, config, enable_streaming)
|
|
93
148
|
|
|
94
149
|
bucket_name = config.details[StorageDetails.BUCKET.value]
|
|
95
150
|
auth_method = config.details[StorageDetails.AUTH_METHOD.value]
|
|
96
151
|
document = None
|
|
97
152
|
|
|
153
|
+
if enable_streaming:
|
|
154
|
+
file_key = f"{privacy_request.id}.zip"
|
|
155
|
+
# Use streaming upload for better memory efficiency
|
|
156
|
+
logger.debug("Using streaming S3 upload for {}", file_key)
|
|
157
|
+
logger.debug("Calling upload_to_s3_streaming with secrets: {}", config.secrets)
|
|
158
|
+
return upload_to_s3_streaming(
|
|
159
|
+
config.secrets, # type: ignore
|
|
160
|
+
data,
|
|
161
|
+
bucket_name,
|
|
162
|
+
file_key,
|
|
163
|
+
config.format.value, # type: ignore
|
|
164
|
+
privacy_request,
|
|
165
|
+
document,
|
|
166
|
+
auth_method,
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
file_key = _construct_file_key(privacy_request.id, config)
|
|
170
|
+
|
|
171
|
+
# Fall back to traditional upload method
|
|
172
|
+
logger.debug("Using traditional S3 upload for {}", file_key)
|
|
98
173
|
return upload_to_s3(
|
|
99
174
|
config.secrets, # type: ignore
|
|
100
175
|
data,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"""Streaming storage module for efficient cloud-to-cloud data transfer."""
|
|
2
|
+
|
|
3
|
+
from .base_storage_client import BaseStorageClient
|
|
4
|
+
from .retry import (
|
|
5
|
+
PermanentError,
|
|
6
|
+
RetryableError,
|
|
7
|
+
RetryConfig,
|
|
8
|
+
TransientError,
|
|
9
|
+
create_retry_config_from_settings,
|
|
10
|
+
is_transient_error,
|
|
11
|
+
retry_cloud_storage_operation,
|
|
12
|
+
retry_with_backoff,
|
|
13
|
+
)
|
|
14
|
+
from .s3.s3_storage_client import S3StorageClient
|
|
15
|
+
from .schemas import AttachmentInfo, StorageUploadConfig, StreamingBufferConfig
|
|
16
|
+
from .smart_open_client import SmartOpenStorageClient
|
|
17
|
+
from .smart_open_streaming_storage import SmartOpenStreamingStorage
|
|
18
|
+
from .storage_client_factory import StorageClientFactory
|
|
19
|
+
|
|
20
|
+
__all__ = [
|
|
21
|
+
# Base classes and interfaces
|
|
22
|
+
"BaseStorageClient",
|
|
23
|
+
"StorageClientFactory",
|
|
24
|
+
# Provider-specific clients
|
|
25
|
+
"S3StorageClient",
|
|
26
|
+
# Main clients
|
|
27
|
+
"SmartOpenStorageClient",
|
|
28
|
+
"SmartOpenStreamingStorage",
|
|
29
|
+
# Schemas
|
|
30
|
+
"StorageUploadConfig",
|
|
31
|
+
"StreamingBufferConfig",
|
|
32
|
+
"AttachmentInfo",
|
|
33
|
+
# Retry utilities
|
|
34
|
+
"RetryConfig",
|
|
35
|
+
"RetryableError",
|
|
36
|
+
"TransientError",
|
|
37
|
+
"PermanentError",
|
|
38
|
+
"retry_with_backoff",
|
|
39
|
+
"retry_cloud_storage_operation",
|
|
40
|
+
"create_retry_config_from_settings",
|
|
41
|
+
"is_transient_error",
|
|
42
|
+
]
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"""Base abstract class for cloud storage clients."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from typing import Any, Optional
|
|
7
|
+
|
|
8
|
+
from fideslang.validation import AnyHttpUrlString
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class BaseStorageClient(ABC):
|
|
12
|
+
"""Abstract base class for cloud storage clients.
|
|
13
|
+
|
|
14
|
+
This class defines the interface that all provider-specific storage clients
|
|
15
|
+
must implement. It provides a common contract for URI building, transport
|
|
16
|
+
parameters, and presigned URL generation.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, storage_secrets: Any):
|
|
20
|
+
"""Initialize the storage client with secrets.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
storage_secrets: Provider-specific storage credentials and configuration.
|
|
24
|
+
Derived classes will specify the exact type they expect.
|
|
25
|
+
"""
|
|
26
|
+
self.storage_secrets = storage_secrets
|
|
27
|
+
|
|
28
|
+
@abstractmethod
|
|
29
|
+
def build_uri(self, bucket: str, key: str) -> str:
|
|
30
|
+
"""Build the URI for the storage location.
|
|
31
|
+
|
|
32
|
+
Args:
|
|
33
|
+
bucket: Storage bucket/container name
|
|
34
|
+
key: Object key/path
|
|
35
|
+
|
|
36
|
+
Returns:
|
|
37
|
+
URI string for smart-open
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
@abstractmethod
|
|
41
|
+
def get_transport_params(self) -> dict[str, Any]:
|
|
42
|
+
"""Get transport parameters for smart-open.
|
|
43
|
+
|
|
44
|
+
Returns:
|
|
45
|
+
Dictionary of transport parameters for smart-open
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
@abstractmethod
|
|
49
|
+
def generate_presigned_url(
|
|
50
|
+
self, bucket: str, key: str, ttl_seconds: Optional[int] = None
|
|
51
|
+
) -> AnyHttpUrlString:
|
|
52
|
+
"""Generate a presigned URL for the object.
|
|
53
|
+
|
|
54
|
+
Args:
|
|
55
|
+
bucket: Storage bucket/container name
|
|
56
|
+
key: Object key/path
|
|
57
|
+
ttl_seconds: Time to live in seconds
|
|
58
|
+
|
|
59
|
+
Returns:
|
|
60
|
+
Presigned URL for the object
|
|
61
|
+
"""
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import zipfile
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from io import BytesIO
|
|
6
|
+
from typing import Any, Generator, Tuple
|
|
7
|
+
|
|
8
|
+
from loguru import logger
|
|
9
|
+
from stream_zip import _ZIP_32_TYPE
|
|
10
|
+
|
|
11
|
+
from fides.api.service.storage.streaming.schemas import AttachmentProcessingInfo
|
|
12
|
+
from fides.api.service.storage.streaming.smart_open_client import SmartOpenStorageClient
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def stream_dsr_buffer_to_storage(
|
|
16
|
+
storage_client: SmartOpenStorageClient,
|
|
17
|
+
bucket_name: str,
|
|
18
|
+
file_key: str,
|
|
19
|
+
dsr_buffer: BytesIO,
|
|
20
|
+
content_type: str = "application/zip",
|
|
21
|
+
) -> None:
|
|
22
|
+
"""Stream DSR buffer to storage using smart-open streaming.
|
|
23
|
+
|
|
24
|
+
This function handles only the storage streaming concern, accepting a pre-generated
|
|
25
|
+
DSR buffer to maintain clear separation of concerns.
|
|
26
|
+
|
|
27
|
+
Args:
|
|
28
|
+
storage_client: The storage client for streaming uploads
|
|
29
|
+
bucket_name: Storage bucket name
|
|
30
|
+
file_key: File key in storage
|
|
31
|
+
dsr_buffer: Pre-generated DSR report buffer (BytesIO)
|
|
32
|
+
content_type: MIME type for the uploaded file (defaults to application/zip)
|
|
33
|
+
"""
|
|
34
|
+
# Get the content from the buffer
|
|
35
|
+
content = dsr_buffer.getvalue()
|
|
36
|
+
try:
|
|
37
|
+
# Use smart-open's streaming upload for efficient memory usage
|
|
38
|
+
with storage_client.stream_upload(
|
|
39
|
+
bucket_name, file_key, content_type=content_type
|
|
40
|
+
) as upload_stream:
|
|
41
|
+
upload_stream.write(content)
|
|
42
|
+
|
|
43
|
+
except Exception as e:
|
|
44
|
+
logger.error("Failed to upload DSR report using smart-open streaming: {}", e)
|
|
45
|
+
raise e
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def create_dsr_report_files_generator(
|
|
49
|
+
dsr_buffer: BytesIO,
|
|
50
|
+
all_attachments: list["AttachmentProcessingInfo"],
|
|
51
|
+
bucket_name: str,
|
|
52
|
+
max_workers: int,
|
|
53
|
+
batch_size: int,
|
|
54
|
+
) -> Generator[
|
|
55
|
+
Tuple[str, datetime, int, Any, Generator[bytes, None, None]], None, None
|
|
56
|
+
]:
|
|
57
|
+
"""Create a ZIP generator for DSR report HTML files only.
|
|
58
|
+
|
|
59
|
+
This method extracts and yields the HTML files from a DSR report buffer.
|
|
60
|
+
Note: This function only handles the DSR report files (HTML, CSS, etc.).
|
|
61
|
+
The caller is responsible for combining this with attachment files to create
|
|
62
|
+
the complete ZIP.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
dsr_buffer: The DSR report buffer (ZIP file as BytesIO)
|
|
66
|
+
all_attachments: List of validated attachments (used for logging only)
|
|
67
|
+
bucket_name: Storage bucket name (used for logging only)
|
|
68
|
+
max_workers: Maximum parallel workers (used for logging only)
|
|
69
|
+
batch_size: Number of attachments to process in each batch (used for logging only)
|
|
70
|
+
|
|
71
|
+
Returns:
|
|
72
|
+
Generator yielding DSR report files in stream_zip format
|
|
73
|
+
"""
|
|
74
|
+
logger.debug(
|
|
75
|
+
f"Creating DSR report files generator with {len(all_attachments)} attachments"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
# Reset buffer position to ensure we can read from it
|
|
79
|
+
dsr_buffer.seek(0)
|
|
80
|
+
|
|
81
|
+
# Extract and yield the DSR report files from the buffer
|
|
82
|
+
# The dsr_buffer is already a ZIP file, so we need to extract and re-yield its contents
|
|
83
|
+
with zipfile.ZipFile(dsr_buffer) as dsr_zip:
|
|
84
|
+
for file_info in dsr_zip.filelist:
|
|
85
|
+
if not file_info.is_dir():
|
|
86
|
+
# Read the file content and yield it in stream_zip format
|
|
87
|
+
content = dsr_zip.read(file_info.filename)
|
|
88
|
+
|
|
89
|
+
def content_generator(
|
|
90
|
+
file_content: bytes,
|
|
91
|
+
) -> Generator[bytes, None, None]:
|
|
92
|
+
yield file_content
|
|
93
|
+
|
|
94
|
+
yield file_info.filename, datetime.now(), 0o644, _ZIP_32_TYPE(), content_generator(
|
|
95
|
+
content
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
logger.debug("DSR report files extracted and ready for ZIP creation")
|