ethyca-fides 2.68.1b2__py2.py3-none-any.whl → 2.68.1b3__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.1b3.dist-info}/METADATA +3 -1
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b3.dist-info}/RECORD +231 -216
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/90502bcda282_update_request_tasks_add_polling_async.py +35 -0
- fides/api/api/v1/endpoints/privacy_request_endpoints.py +1 -1
- fides/api/common_exceptions.py +12 -3
- fides/api/models/detection_discovery/core.py +6 -0
- fides/api/models/privacy_request/request_task.py +25 -0
- fides/api/schemas/privacy_center_config.py +48 -19
- fides/api/schemas/storage/storage.py +2 -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_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/config/execution_settings.py +4 -0
- fides/service/privacy_request/privacy_request_service.py +1 -9
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/_BLI2ArqQzY5XnXbrcxa2/_buildManifest.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1099-7b2085a3931da9e4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1138-0d846ffef62c580f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1345-ab756811e19ff4fc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{1817-c90365325f8a3d75.js → 1817-fd21f1f5ef0faffa.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{1975.e5cc7a1ccd477671.js → 1975.16126463309143e3.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{2921-46f9465c2852a46b.js → 2921-0e5cc63a82e31830.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/3620-6cceae71bae5b531.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3729-7d2d52400f1f7413.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3855-64541570e2f838fb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3872-7a18d18a5e287e4e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3923-a33633feba5e655e.js → 3923-5c87b3d7f1626678.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{401-741bb31b586b7c96.js → 401-3902e3e98790d401.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{4121-94354b50a41f8497.js → 4121-64ef70ef906bbdd0.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-70521532195124de.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4786-53ef1662f2d0d98c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4808-8713433c84a62efe.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4844-351f99b6644b654e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5258-c6f96dc740eb5fb1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5487-338800277d36b8d7.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/549-e6453a3526023e85.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/602-80d113e801d7407d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{6084-02abe12327fc3dbc.js → 6084-da63f20d9416a982.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{6853-270261ef5537a106.js → 6853-1d947b75eb07188c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/6954-24f9a4f27d67b732.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7476-a0dd03bfccf60d0c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7630-9fbe06cfb98266fe.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{787-5ba991cad1f7664a.js → 787-3dd31844cf7fec55.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/79-dcd20e8b09501c17.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/796-8773e04b64ce2260.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/8002-dcd02da6e5649a1c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9046-57eab238570b8bf4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9676.bf0a8a6ff6dfd2af.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{9826-8c81c97a72510fcf.js → 9826-756c958aecab59a2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9951-cdf73904a3adb27b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{404-9174cdb70126c2c5.js → 404-dd625a559ada46ca.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-2c10f6b217b7978b.js → _app-b6b09b2878b77b21.js} +136 -135
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-621416493c89ef01.js → manual-92cf5e313be1f9e2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-0b9908c3e1dfe49e.js → multiple-d6c525ee731a2993.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-5664a3ea796e5ffb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-5bb1b31ae8752250.js → add-vendors-78f13de90111fd80.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-0fc678f3d6d2fcec.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-4e4d9426743b5cb4.js → [id]-126db59dc25ca326.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-d72460348fadcab8.js → privacy-experience-289605267d6cce7e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-3e7ddc252da00c98.js → [id]-e9fd9b28ac9705af.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-35a7c305beee9428.js → new-28c003b6043bd16c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-c643eff04525298e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-ab96939421639153.js → properties-3ef5d01779a26455.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-baa4a2f8f08ac224.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{consent-13240e3ca77acfeb.js → consent-8d4be9e7ec7d2a35.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-aad6047a4604b945.js → [resourceUrn]-f27ec4578c674181.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-bd37b407c80c6986.js → [projectUrn]-27b6c255bd9e73b6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects-0f66dac32040519c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-b6b98cea25dd94fa.js → [resourceUrn]-3b938562df81c4b0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog-ebf5e7fa4e2ffb49.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-b27c660039d951c9.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-8ce5d24af470888e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-8e35e33928abbcdc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/activity-21c141279e66237a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-31e6c54794a9883e.js → [resourceUrn]-3bc6a207693fd175.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-2822a423a7ad0550.js → detection-da16e73df395ad1d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-f98dd251babb7e28.js → [resourceUrn]-04b242632a114405.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-56eb4c014f0d96a3.js → discovery-900fe50183a40d72.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-8f88dc31c5144ea8.js → datamap-4f1f7c3a9531a8f4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/[...subfieldNames]-343294dcb10d9532.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]-1c097a0809fa5b6f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]-b47fa2498b534719.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-a31f881cab25704a.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-858c59c9e67e318d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-67a7fe58b96ea739.js → [id]-16c28d272225afb6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{new-90a8df230cb89877.js → new-68f502d8b0b5792c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-1eb9acb17b133fd1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{index-876bfd7210040cec.js → index-fec557d99211f577.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/{[id]-4e286a1e501a0c73.js → [id]-e613543818d6cbd2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-8069f7c33695fd45.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-6e796c3fe632280b.js → [id]-4a08ca7762a19700.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-fa0f3841c5bdfdeb.js → add-template-343a965dcdb3d11e.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/messaging-3ade4c54b1c8a11e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/ant-components-9103bfb854f71410.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{AntForm-11503454a62d8d7b.js → AntForm-3b97029bd4d3c3ea.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikAntFormItem-a504941807bdb7f1.js → FormikAntFormItem-9d9beb8f0d8a278c.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikControlled-0119403c8ff97f83.js → FormikControlled-84a4d8fc60f839ed.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikField-94f6d57d6c94ddf7.js → FormikField-1fccf542ab2e33bf.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/{forms-ed1a3ae09d72df89.js → forms-aa75263ae1ba67bb.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-db334a1cbb102255.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-11c1e4545c8f528c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-192a986f61c23268.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-9216ac993d71387e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure-e55ec84d5380401d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-48f447b31c786b80.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-41976b28503623cd.js → [id]-a74b51b704b80cb2.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-cb438d8f5ec6007a.js → add-property-8d23f0c55ff6510a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{properties-b6db7036993709b3.js → properties-77acceac4f99e7af.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/{datamap-4bc3e281409265cc.js → datamap-e60d398e255f4e00.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about/alpha-6aad3f563ed03b3f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/about-c1b8f3606d160bb1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-d9f7f78810d58d08.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-ee2c7dde99b1dafb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-a4dad8ca9de2d07b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-386368bf7cb31771.js → domain-records-31c270d228e00581.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/domains-996b3f250dd3ea1f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/email-templates-ee94981326ddcbf4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{locations-b41fb5ad277088ab.js → locations-0b831c58966782b8.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/organization-94271ba4a224a353.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-a94dfeea43fbca7d.js → regulations-41b8136e50320fd3.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/test-datasets-52b45569cbc82e60.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-18b316e2dad73731.js → [id]-36d74e93e54aabaf.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems-24dfc8e2279ced2e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-d9675cf5e6083b27.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/{[id]-3237881945acc0ee.js → [id]-866826d7959df487.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{user-management-a3a50d9d79066935.js → user-management-e63b61a8f99ccd57.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{webpack-69658aeaf6155d89.js → webpack-6d0a487039bcf30c.js} +1 -1
- fides/ui-build/static/admin/_next/static/css/{a72179b1754aadd3.css → 92441453b27e9c34.css} +1 -1
- 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/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-cfb25b02abb8da71.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/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/qvk5eMANVfwYkdURE7fgG/_buildManifest.js +0 -1
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b3.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b3.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b3.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.68.1b2.dist-info → ethyca_fides-2.68.1b3.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{qvk5eMANVfwYkdURE7fgG → _BLI2ArqQzY5XnXbrcxa2}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"""S3-specific storage client implementation."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Any, Optional
|
|
6
|
+
|
|
7
|
+
from fideslang.validation import AnyHttpUrlString
|
|
8
|
+
from loguru import logger
|
|
9
|
+
|
|
10
|
+
from fides.api.schemas.storage.storage import AWSAuthMethod, StorageSecrets
|
|
11
|
+
from fides.api.service.storage.s3 import create_presigned_url_for_s3
|
|
12
|
+
from fides.api.service.storage.streaming.base_storage_client import BaseStorageClient
|
|
13
|
+
from fides.api.util.aws_util import get_s3_client
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class S3StorageClient(BaseStorageClient):
|
|
17
|
+
"""S3-specific storage client implementation.
|
|
18
|
+
|
|
19
|
+
Handles S3-specific URI construction, transport parameters, and presigned URL
|
|
20
|
+
generation for the smart-open storage client.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
def __init__(self, storage_secrets: dict[StorageSecrets, Any]):
|
|
24
|
+
"""Initialize the storage client with secrets.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
storage_secrets: Provider-specific storage credentials and configuration using StorageSecrets enum keys
|
|
28
|
+
"""
|
|
29
|
+
super().__init__(storage_secrets)
|
|
30
|
+
self.storage_secrets: dict[StorageSecrets, Any] = storage_secrets
|
|
31
|
+
|
|
32
|
+
def build_uri(self, bucket: str, key: str) -> str:
|
|
33
|
+
"""Build the S3 URI for the storage location.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
bucket: S3 bucket name
|
|
37
|
+
key: Object key/path
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
S3 URI string for smart-open
|
|
41
|
+
"""
|
|
42
|
+
# Handle custom endpoint (e.g., MinIO) - endpoint_url is not in StorageSecrets enum
|
|
43
|
+
# For now, we'll use standard S3 URI since we only have enum keys
|
|
44
|
+
return f"s3://{bucket}/{key}"
|
|
45
|
+
|
|
46
|
+
def get_transport_params(self) -> dict[str, Any]:
|
|
47
|
+
"""Get S3-specific transport parameters for smart-open.
|
|
48
|
+
|
|
49
|
+
Returns:
|
|
50
|
+
Dictionary of S3 transport parameters for smart-open
|
|
51
|
+
"""
|
|
52
|
+
params = {}
|
|
53
|
+
|
|
54
|
+
if StorageSecrets.AWS_ACCESS_KEY_ID in self.storage_secrets:
|
|
55
|
+
params["access_key"] = self.storage_secrets[
|
|
56
|
+
StorageSecrets.AWS_ACCESS_KEY_ID
|
|
57
|
+
]
|
|
58
|
+
if StorageSecrets.AWS_SECRET_ACCESS_KEY in self.storage_secrets:
|
|
59
|
+
params["secret_key"] = self.storage_secrets[
|
|
60
|
+
StorageSecrets.AWS_SECRET_ACCESS_KEY
|
|
61
|
+
]
|
|
62
|
+
if StorageSecrets.REGION_NAME in self.storage_secrets:
|
|
63
|
+
params["region"] = self.storage_secrets[StorageSecrets.REGION_NAME]
|
|
64
|
+
if StorageSecrets.AWS_ASSUME_ROLE in self.storage_secrets:
|
|
65
|
+
params["assume_role_arn"] = self.storage_secrets[
|
|
66
|
+
StorageSecrets.AWS_ASSUME_ROLE
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
return params
|
|
70
|
+
|
|
71
|
+
def generate_presigned_url(
|
|
72
|
+
self, bucket: str, key: str, ttl_seconds: Optional[int] = None
|
|
73
|
+
) -> AnyHttpUrlString:
|
|
74
|
+
"""Generate an S3 presigned URL for the object.
|
|
75
|
+
|
|
76
|
+
Args:
|
|
77
|
+
bucket: S3 bucket name
|
|
78
|
+
key: Object key/path
|
|
79
|
+
ttl_seconds: Time to live in seconds
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
S3 presigned URL for the object
|
|
83
|
+
|
|
84
|
+
Raises:
|
|
85
|
+
Exception: If presigned URL generation fails
|
|
86
|
+
"""
|
|
87
|
+
try:
|
|
88
|
+
# Storage secrets are already in the right format for get_s3_client
|
|
89
|
+
# get_s3_client expects dict[StorageSecrets, Any] with enum keys
|
|
90
|
+
s3_secrets = self.storage_secrets
|
|
91
|
+
|
|
92
|
+
# Determine auth method based on available credentials
|
|
93
|
+
# If AWS credentials are present, use SECRET_KEYS, otherwise use AUTOMATIC
|
|
94
|
+
if (
|
|
95
|
+
StorageSecrets.AWS_ACCESS_KEY_ID in self.storage_secrets
|
|
96
|
+
and StorageSecrets.AWS_SECRET_ACCESS_KEY in self.storage_secrets
|
|
97
|
+
and self.storage_secrets[StorageSecrets.AWS_ACCESS_KEY_ID]
|
|
98
|
+
and self.storage_secrets[StorageSecrets.AWS_SECRET_ACCESS_KEY]
|
|
99
|
+
):
|
|
100
|
+
auth_method = AWSAuthMethod.SECRET_KEYS.value
|
|
101
|
+
else:
|
|
102
|
+
auth_method = AWSAuthMethod.AUTOMATIC.value
|
|
103
|
+
|
|
104
|
+
# Extract assume_role_arn if present for role assumption
|
|
105
|
+
assume_role_arn = None
|
|
106
|
+
if StorageSecrets.AWS_ASSUME_ROLE in self.storage_secrets:
|
|
107
|
+
assume_role_arn = self.storage_secrets[StorageSecrets.AWS_ASSUME_ROLE]
|
|
108
|
+
|
|
109
|
+
s3_client = get_s3_client(auth_method, s3_secrets, assume_role_arn)
|
|
110
|
+
return create_presigned_url_for_s3(s3_client, bucket, key, ttl_seconds)
|
|
111
|
+
except Exception as e:
|
|
112
|
+
logger.error(f"Failed to generate S3 presigned URL: {e}")
|
|
113
|
+
raise
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from io import BytesIO
|
|
4
|
+
from typing import Any, Optional, Union
|
|
5
|
+
|
|
6
|
+
from fideslang.validation import AnyHttpUrlString
|
|
7
|
+
from loguru import logger
|
|
8
|
+
|
|
9
|
+
from fides.api.common_exceptions import StorageUploadError
|
|
10
|
+
from fides.api.models.privacy_request import PrivacyRequest
|
|
11
|
+
from fides.api.schemas.storage.storage import StorageSecrets, StorageSecretsS3
|
|
12
|
+
from fides.api.service.storage.s3 import generic_upload_to_s3
|
|
13
|
+
from fides.api.service.storage.streaming.retry import retry_cloud_storage_operation
|
|
14
|
+
from fides.api.service.storage.streaming.schemas import StorageUploadConfig
|
|
15
|
+
from fides.api.service.storage.streaming.smart_open_client import SmartOpenStorageClient
|
|
16
|
+
from fides.api.service.storage.streaming.smart_open_streaming_storage import (
|
|
17
|
+
SmartOpenStreamingStorage,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
@retry_cloud_storage_operation(
|
|
22
|
+
provider="s3_streaming",
|
|
23
|
+
operation_name="upload_to_s3_streaming",
|
|
24
|
+
max_retries=2,
|
|
25
|
+
base_delay=2.0,
|
|
26
|
+
max_delay=30.0,
|
|
27
|
+
)
|
|
28
|
+
def upload_to_s3_streaming(
|
|
29
|
+
storage_secrets: Union[StorageSecretsS3, dict[StorageSecrets, Any]],
|
|
30
|
+
data: dict,
|
|
31
|
+
bucket_name: str,
|
|
32
|
+
file_key: str,
|
|
33
|
+
resp_format: str,
|
|
34
|
+
privacy_request: PrivacyRequest,
|
|
35
|
+
document: Optional[BytesIO],
|
|
36
|
+
auth_method: str,
|
|
37
|
+
max_workers: int = 5,
|
|
38
|
+
) -> Optional[AnyHttpUrlString]:
|
|
39
|
+
"""Uploads arbitrary data to S3 using smart-open streaming for memory efficiency.
|
|
40
|
+
|
|
41
|
+
This function now uses smart-open for efficient cloud storage operations while maintaining
|
|
42
|
+
our DSR-specific business logic for package splitting and attachment processing.
|
|
43
|
+
"""
|
|
44
|
+
formatted_secrets = format_secrets(storage_secrets)
|
|
45
|
+
|
|
46
|
+
if document is not None:
|
|
47
|
+
_, response = generic_upload_to_s3(
|
|
48
|
+
formatted_secrets, # type: ignore[arg-type]
|
|
49
|
+
bucket_name,
|
|
50
|
+
file_key,
|
|
51
|
+
auth_method,
|
|
52
|
+
document,
|
|
53
|
+
)
|
|
54
|
+
return response
|
|
55
|
+
|
|
56
|
+
try:
|
|
57
|
+
storage_client = SmartOpenStorageClient("s3", formatted_secrets)
|
|
58
|
+
|
|
59
|
+
# Create upload config for the streaming interface
|
|
60
|
+
upload_config = StorageUploadConfig(
|
|
61
|
+
bucket_name=bucket_name,
|
|
62
|
+
file_key=file_key,
|
|
63
|
+
resp_format=resp_format,
|
|
64
|
+
max_workers=max_workers,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
# Use the smart-open streaming implementation
|
|
68
|
+
streaming_storage = SmartOpenStreamingStorage(storage_client)
|
|
69
|
+
result = streaming_storage.upload_to_storage_streaming(
|
|
70
|
+
data,
|
|
71
|
+
upload_config,
|
|
72
|
+
privacy_request,
|
|
73
|
+
document,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
logger.debug(
|
|
77
|
+
"Successfully uploaded streaming archive to S3 using smart-open: {}",
|
|
78
|
+
file_key,
|
|
79
|
+
)
|
|
80
|
+
return result
|
|
81
|
+
|
|
82
|
+
except Exception as e:
|
|
83
|
+
logger.error("Unexpected error during smart-open streaming upload: {}", e)
|
|
84
|
+
raise StorageUploadError(
|
|
85
|
+
f"Unexpected error during smart-open streaming upload: {e}"
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _process_storage_secrets_input(
|
|
90
|
+
storage_secrets: Union[StorageSecretsS3, dict[StorageSecrets, Any]] # type: ignore[misc]
|
|
91
|
+
) -> dict[str, Any]:
|
|
92
|
+
"""Process input and convert to string-keyed dictionary."""
|
|
93
|
+
final_secrets: dict[str, Any] = {}
|
|
94
|
+
|
|
95
|
+
if isinstance(storage_secrets, StorageSecretsS3):
|
|
96
|
+
# Convert StorageSecretsS3 model directly to string keys
|
|
97
|
+
for key, value in storage_secrets.model_dump().items():
|
|
98
|
+
if value is not None:
|
|
99
|
+
final_secrets[key] = value
|
|
100
|
+
else:
|
|
101
|
+
# Process dict input, converting enum keys to strings if needed
|
|
102
|
+
for key, value in (storage_secrets or {}).items(): # type: ignore[assignment]
|
|
103
|
+
if isinstance(key, str):
|
|
104
|
+
final_secrets[key] = value
|
|
105
|
+
elif isinstance(key, StorageSecrets):
|
|
106
|
+
final_secrets[key.value] = value
|
|
107
|
+
|
|
108
|
+
return final_secrets
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _validate_aws_credentials(final_secrets: dict[str, Any]) -> None:
|
|
112
|
+
"""Validate that required AWS credentials are present."""
|
|
113
|
+
has_access_key = (
|
|
114
|
+
"aws_access_key_id" in final_secrets and final_secrets["aws_access_key_id"]
|
|
115
|
+
)
|
|
116
|
+
has_secret_key = (
|
|
117
|
+
"aws_secret_access_key" in final_secrets
|
|
118
|
+
and final_secrets["aws_secret_access_key"]
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
# If we have any AWS credentials, we need both for SECRET_KEYS auth
|
|
122
|
+
if has_access_key or has_secret_key:
|
|
123
|
+
if not has_access_key:
|
|
124
|
+
raise ValueError(
|
|
125
|
+
"Missing required AWS credentials for SECRET_KEYS auth: aws_access_key_id. "
|
|
126
|
+
"Storage configuration must include valid AWS access key and secret key."
|
|
127
|
+
)
|
|
128
|
+
if not has_secret_key:
|
|
129
|
+
raise ValueError(
|
|
130
|
+
"Missing required AWS credentials for SECRET_KEYS auth: aws_secret_access_key. "
|
|
131
|
+
"Storage configuration must include valid AWS access key and secret key."
|
|
132
|
+
)
|
|
133
|
+
else:
|
|
134
|
+
# AUTOMATIC authentication - check if region is provided
|
|
135
|
+
has_region = "region_name" in final_secrets and final_secrets["region_name"]
|
|
136
|
+
if not has_region:
|
|
137
|
+
raise ValueError(
|
|
138
|
+
"Missing required region_name for AUTOMATIC authentication. "
|
|
139
|
+
"Storage configuration must include a valid AWS region."
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def _set_default_region(final_secrets: dict[str, Any]) -> None:
|
|
144
|
+
"""Set default region if missing."""
|
|
145
|
+
if "region_name" not in final_secrets or not final_secrets["region_name"]:
|
|
146
|
+
logger.debug("Setting default region to 'us-east-1'")
|
|
147
|
+
final_secrets["region_name"] = "us-east-1"
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def format_secrets(
|
|
151
|
+
storage_secrets: Union[StorageSecretsS3, dict[StorageSecrets, Any]] # type: ignore[misc]
|
|
152
|
+
) -> dict[str, Any]:
|
|
153
|
+
"""
|
|
154
|
+
Returns the correct format for the S3StorageClient.
|
|
155
|
+
|
|
156
|
+
This function handles multiple credential formats and processes them through several stages:
|
|
157
|
+
1. Input processing: Accepts either StorageSecretsS3 models (from API) or raw dicts (from database)
|
|
158
|
+
2. Key normalization: Converts all keys to string format for consistency
|
|
159
|
+
3. Validation: Ensures required AWS credentials are present based on auth method
|
|
160
|
+
4. Default setting: Sets default region if missing (after validation)
|
|
161
|
+
5. Return: Returns string-keyed dict ready for S3StorageClient
|
|
162
|
+
|
|
163
|
+
Input formats:
|
|
164
|
+
- StorageSecretsS3: Used by storage API endpoints (e.g., put_config_secrets)
|
|
165
|
+
- dict[StorageSecrets, Any]: Used by storage models (e.g., StorageConfig.secrets)
|
|
166
|
+
- dict[str, Any]: Used by database queries (e.g., StorageConfig.get_by)
|
|
167
|
+
|
|
168
|
+
Authentication methods:
|
|
169
|
+
- SECRET_KEYS: Requires aws_access_key_id, aws_secret_access_key, and region_name
|
|
170
|
+
- AUTOMATIC: Requires only region_name (relies on AWS SDK credential chain)
|
|
171
|
+
- Role assumption: Can be used with either auth method via assume_role_arn
|
|
172
|
+
|
|
173
|
+
Output format:
|
|
174
|
+
- dict[str, Any]: Required by S3StorageClient.generate_presigned_url() and other AWS operations
|
|
175
|
+
|
|
176
|
+
Returns:
|
|
177
|
+
dict[str, Any]: Credentials with string keys like 'aws_access_key_id'
|
|
178
|
+
|
|
179
|
+
Raises:
|
|
180
|
+
ValueError: If required AWS credentials are missing for the chosen auth method
|
|
181
|
+
"""
|
|
182
|
+
logger.debug("format_secrets called with type: {}", type(storage_secrets).__name__)
|
|
183
|
+
|
|
184
|
+
# Stage 1: Process input and create final format directly
|
|
185
|
+
final_secrets = _process_storage_secrets_input(storage_secrets)
|
|
186
|
+
|
|
187
|
+
# Stage 2: Validate required credentials BEFORE setting defaults
|
|
188
|
+
_validate_aws_credentials(final_secrets)
|
|
189
|
+
|
|
190
|
+
# Stage 3: Set default region if missing (after validation)
|
|
191
|
+
_set_default_region(final_secrets)
|
|
192
|
+
|
|
193
|
+
logger.debug(
|
|
194
|
+
"format_secrets completed successfully with {} keys", len(final_secrets)
|
|
195
|
+
)
|
|
196
|
+
return final_secrets
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
from typing import Annotated, Any, Optional
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel, Field, field_validator
|
|
4
|
+
|
|
5
|
+
# multipart upload requirements
|
|
6
|
+
MIN_PART_SIZE = 5 * 1024 * 1024 # 5MB minimum part size for AWS S3 uploads
|
|
7
|
+
ZIP_BUFFER_THRESHOLD = 5 * 1024 * 1024 # 5MB threshold for zip buffer uploads
|
|
8
|
+
CHUNK_SIZE_THRESHOLD = 5 * 1024 * 1024 # 5MB threshold for chunk-based uploads
|
|
9
|
+
LARGE_FILE_THRESHOLD = 25 * 1024 * 1024 # 25MB threshold for large file handling
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class AttachmentInfo(BaseModel):
|
|
13
|
+
"""Schema for attachment information in streaming storage"""
|
|
14
|
+
|
|
15
|
+
storage_key: str = Field(
|
|
16
|
+
..., description="Storage key for the attachment (cloud-agnostic)"
|
|
17
|
+
)
|
|
18
|
+
file_name: Optional[str] = Field(None, description="Human-readable filename")
|
|
19
|
+
size: Optional[int] = Field(None, ge=0, description="File size in bytes")
|
|
20
|
+
content_type: Optional[str] = Field(None, description="MIME type of the file")
|
|
21
|
+
|
|
22
|
+
@field_validator("storage_key")
|
|
23
|
+
@classmethod
|
|
24
|
+
def validate_storage_key(cls, v: str) -> str:
|
|
25
|
+
if not v or not v.strip():
|
|
26
|
+
raise ValueError("storage_key cannot be empty or whitespace")
|
|
27
|
+
return v.strip()
|
|
28
|
+
|
|
29
|
+
@field_validator("file_name")
|
|
30
|
+
@classmethod
|
|
31
|
+
def validate_file_name(cls, v: Optional[str]) -> Optional[str]:
|
|
32
|
+
if v is not None and (not v or not v.strip()):
|
|
33
|
+
raise ValueError("file_name cannot be empty or whitespace if provided")
|
|
34
|
+
return v.strip() if v else None
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class StorageUploadConfig(BaseModel):
|
|
38
|
+
"""Configuration for storage upload operations"""
|
|
39
|
+
|
|
40
|
+
bucket_name: str = Field(..., description="Storage bucket name")
|
|
41
|
+
file_key: str = Field(..., description="File key in storage")
|
|
42
|
+
max_workers: int = Field(
|
|
43
|
+
default=5, ge=1, le=20, description="Maximum parallel workers"
|
|
44
|
+
)
|
|
45
|
+
resp_format: str = Field(..., description="Response format (csv, json, html)")
|
|
46
|
+
|
|
47
|
+
@field_validator("bucket_name", "file_key")
|
|
48
|
+
@classmethod
|
|
49
|
+
def validate_storage_identifiers(cls, v: str) -> str:
|
|
50
|
+
if not v or not v.strip():
|
|
51
|
+
raise ValueError("Storage identifier cannot be empty or whitespace")
|
|
52
|
+
return v.strip()
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class PackageSplitConfig(BaseModel):
|
|
56
|
+
"""Configuration for package splitting operations"""
|
|
57
|
+
|
|
58
|
+
max_attachments: int = Field(
|
|
59
|
+
default=100, ge=1, le=1000, description="Max attachments per package"
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
@field_validator("max_attachments")
|
|
63
|
+
@classmethod
|
|
64
|
+
def validate_max_attachments(cls, v: int) -> int:
|
|
65
|
+
if v < 1:
|
|
66
|
+
raise ValueError("max_attachments must be at least 1")
|
|
67
|
+
return v
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class StreamingBufferConfig(BaseModel):
|
|
71
|
+
"""Configuration for streaming buffer operations"""
|
|
72
|
+
|
|
73
|
+
zip_buffer_threshold: int = Field(
|
|
74
|
+
default=5 * 1024 * 1024,
|
|
75
|
+
ge=1024 * 1024,
|
|
76
|
+
description="Zip buffer threshold in bytes (default: 5MB)",
|
|
77
|
+
)
|
|
78
|
+
stream_buffer_threshold: int = Field(
|
|
79
|
+
default=1024 * 1024,
|
|
80
|
+
ge=1024 * 1024,
|
|
81
|
+
description="Stream buffer threshold in bytes (default: 1MB)",
|
|
82
|
+
)
|
|
83
|
+
chunk_size_threshold: int = Field(
|
|
84
|
+
default=1024 * 1024,
|
|
85
|
+
ge=1024 * 1024,
|
|
86
|
+
description="Chunk size threshold in bytes (default: 1MB)",
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
class AttachmentProcessingInfo(BaseModel):
|
|
91
|
+
"""Information for processing a single attachment"""
|
|
92
|
+
|
|
93
|
+
attachment: AttachmentInfo = Field(..., description="Attachment to process")
|
|
94
|
+
base_path: str = Field(..., description="Base path for the attachment in the zip")
|
|
95
|
+
item: dict[str, Any] = Field(..., description="Associated item data")
|
|
96
|
+
|
|
97
|
+
@field_validator("base_path")
|
|
98
|
+
@classmethod
|
|
99
|
+
def validate_base_path(cls, v: str) -> str:
|
|
100
|
+
if not v or not v.strip():
|
|
101
|
+
raise ValueError("base_path cannot be empty or whitespace")
|
|
102
|
+
return v.strip()
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class MultipartUploadResponse(BaseModel):
|
|
106
|
+
"""Response from initiating a multipart upload"""
|
|
107
|
+
|
|
108
|
+
upload_id: Annotated[
|
|
109
|
+
str, Field(..., description="Unique identifier for the multipart upload")
|
|
110
|
+
]
|
|
111
|
+
metadata: Optional[dict[str, Any]] = Field(
|
|
112
|
+
default=None, description="Additional metadata from the storage provider"
|
|
113
|
+
)
|
|
114
|
+
|
|
115
|
+
model_config = {
|
|
116
|
+
"extra": "allow", # Allow extra fields from storage providers
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@field_validator("upload_id")
|
|
120
|
+
@classmethod
|
|
121
|
+
def validate_upload_id(cls, v: Any) -> str:
|
|
122
|
+
"""Validate upload ID is not empty or whitespace."""
|
|
123
|
+
if not isinstance(v, str):
|
|
124
|
+
raise ValueError("Upload ID must be a string")
|
|
125
|
+
if not v or not v.strip():
|
|
126
|
+
raise ValueError("Upload ID cannot be empty or whitespace")
|
|
127
|
+
return v.strip()
|
|
128
|
+
|
|
129
|
+
def is_valid_upload_id(self) -> bool:
|
|
130
|
+
"""Check if the upload ID is valid (not empty or whitespace)"""
|
|
131
|
+
return bool(self.upload_id and self.upload_id.strip())
|
|
132
|
+
|
|
133
|
+
def get_provider_metadata(self, key: str, default: Any = None) -> Any:
|
|
134
|
+
"""Get metadata value by key with fallback to default"""
|
|
135
|
+
if self.metadata is not None:
|
|
136
|
+
return self.metadata.get(key, default) # pylint: disable=no-member
|
|
137
|
+
return default
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
class UploadPartResponse(BaseModel):
|
|
141
|
+
"""Response from uploading a part"""
|
|
142
|
+
|
|
143
|
+
etag: Annotated[str, Field(..., description="ETag/checksum of the uploaded part")]
|
|
144
|
+
part_number: Annotated[
|
|
145
|
+
int, Field(..., description="Sequential number of the part (1-10,000)")
|
|
146
|
+
]
|
|
147
|
+
metadata: Optional[dict[str, Any]] = Field(
|
|
148
|
+
default=None, description="Additional metadata from the storage provider"
|
|
149
|
+
)
|
|
150
|
+
|
|
151
|
+
model_config = {
|
|
152
|
+
"extra": "allow", # Allow extra fields from storage providers
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
@field_validator("part_number")
|
|
156
|
+
@classmethod
|
|
157
|
+
def validate_part_number(cls, v: Any) -> int:
|
|
158
|
+
"""Validate part number is within AWS S3 limits (1-10,000)."""
|
|
159
|
+
if not isinstance(v, int):
|
|
160
|
+
raise ValueError("Part number must be an integer")
|
|
161
|
+
if v < 1 or v > 10000:
|
|
162
|
+
raise ValueError("Part number must be between 1 and 10,000")
|
|
163
|
+
return v
|
|
164
|
+
|
|
165
|
+
def is_valid_etag(self) -> bool:
|
|
166
|
+
"""Check if the ETag is valid (not empty and properly formatted)"""
|
|
167
|
+
return bool(self.etag and self.etag.strip())
|
|
168
|
+
|
|
169
|
+
def get_provider_metadata(self, key: str, default: Any = None) -> Any:
|
|
170
|
+
"""Get metadata value by key with fallback to default"""
|
|
171
|
+
if self.metadata is not None:
|
|
172
|
+
return self.metadata.get(key, default) # pylint: disable=no-member
|
|
173
|
+
return default
|