ethyca-fides 2.62.0rc0__py2.py3-none-any.whl → 2.62.1b1__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.
- {ethyca_fides-2.62.0rc0.dist-info → ethyca_fides-2.62.1b1.dist-info}/METADATA +2 -1
- {ethyca_fides-2.62.0rc0.dist-info → ethyca_fides-2.62.1b1.dist-info}/RECORD +218 -216
- {ethyca_fides-2.62.0rc0.dist-info → ethyca_fides-2.62.1b1.dist-info}/WHEEL +1 -1
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/2263583b0e44_add_shared_monitor_config.py +82 -0
- fides/api/api/v1/endpoints/privacy_request_endpoints.py +2 -2
- fides/api/models/attachment.py +117 -10
- fides/api/models/detection_discovery.py +66 -1
- fides/api/models/privacy_request/privacy_request.py +40 -1
- fides/api/service/privacy_request/dsr_package/dsr_report_builder.py +4 -2
- fides/api/service/storage/s3.py +40 -15
- fides/api/tasks/storage.py +2 -2
- fides/api/util/storage_util.py +14 -8
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/Sez6kqW5dI0lK60IMwICO/_buildManifest.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1327-da0303f70d12fb20.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1817-d2543e460cec0dcb.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/1904-25e5d4f1b8146fb3.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{2310-0d63c66c2685e83c.js → 2310-6a5fb2f76f7b6491.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/3119-b5e40d8d24af1e79.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/3426-77fccf2c9a5e10cd.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{3513-87b54d931698986f.js → 3513-293b1e54699cf3e7.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/{3872-6b828cb00fb2ce93.js → 3872-99da5bb6140ff810.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/3923-c6dcaeaa3267f254.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/401-a882199f6c94a4dc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4060-c657e58514e91e91.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4121-ec1d8faa3cf5783c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/4481-9357e3930d35073b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5258-49e73e5998c01254.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{5487-62955c11bab63734.js → 5487-218e4847b8250fbb.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/5683-3d5c4194b1b1493e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/5973-d776c0029db45971.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6277-db781b6c1dde3c84.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/6853-348fe2ba132b400c.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{6954-d02d474ba30756b2.js → 6954-04030a21a0c8cf5a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/7553-0f3e9e7eaf1a8b62.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/79-d877d3bde220da44.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/796-7424eb6391142ccd.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/7980-041df432c4d3a68b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/{9494-0df032fe6ee531a5.js → 9494-d1fd4fb83c3d4836.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/9767-f8ea7d0127f81294.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/9965-92f4a28823a5e623.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-371b155655c83a1e.js → _app-94950df9c97cd079.js} +69 -69
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{manual-7d789458fb296270.js → manual-1292fd216f2839c7.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems/{multiple-90320455052466cd.js → multiple-2ffc37614e9d1fa9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-0234733a90ed5127.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure/{add-vendors-bcc515a765c0119d.js → add-vendors-c8033d6560635046.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-2ba21b95aa3bb15e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{privacy-experience-5ef03041a530b0e2.js → privacy-experience-fd71fb440dbe60e4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-5a63fc903408412e.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/{properties-ffa15d7ff64a9f05.js → properties-5960170d492acb03.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-80bd51f8217edae4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/[projectUrn]/{[resourceUrn]-7ddf45ffd49533b0.js → [resourceUrn]-18e3faf7963962e4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/projects/{[projectUrn]-ecf23116a845188a.js → [projectUrn]-a10a0f3e6592f350.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{projects-79f8e613827c55c1.js → projects-6971531bb09dff3a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/resources/{[resourceUrn]-ed213bc1b7041aa2.js → [resourceUrn]-7320524a47104798.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-catalog/[systemId]/{resources-1f033ca5a0702018.js → resources-51d99174c8006eb5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{data-catalog-e950d41b75f86c85.js → data-catalog-4dbc71d8be9765f3.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-67ddc090cf949af4.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-07ff657ee49e5742.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-dbc8c95c22b9f2aa.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{activity-beedbc38ee2b0094.js → activity-db3853a09933097a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/detection/{[resourceUrn]-f38b3ef885a29ea6.js → [resourceUrn]-4c526db0c30c488a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{detection-29fd0d5a73f13a00.js → detection-6f27dbb7c8edc69d.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/discovery/{[resourceUrn]-9a80241f1028c470.js → [resourceUrn]-562d2b8ae90dd1f0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/{discovery-c58333981b1522c9.js → discovery-fe7f51502eda57c9.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{datamap-2d6f95b2769a0936.js → datamap-3aaa99709d83a1f6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/[collectionName]/{[...subfieldNames]-3536ae978741b659.js → [...subfieldNames]-c08363922838022a.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/[datasetId]/{[collectionName]-8b5afe14cf42a4ac.js → [collectionName]-f12df2140e309dfb.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/{[datasetId]-b8dca4298b5bb085.js → [datasetId]-3f564c8d6cfb03d4.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-157b00d23b651d12.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-9d29dd6cf109891d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/{[id]-ebf54ea9874c59ae.js → [id]-b078218865a8fd28.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-b01f89d250ff52af.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-9fc15228581786e6.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{index-868b60407eae35da.js → index-2e6ba5382358fcf8.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-43abc599f0768331.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-d69c9f1007e76046.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{messaging-5f41afae411cd8a4.js → messaging-71166bf207804754.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/poc/table-migration-fec150afcfeb3fb5.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-2862630f0e9e484b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-35e58b5ed6b12b2b.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-bb02092af39446da.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-6baa485385ce0678.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/{properties-f00530710b699afd.js → properties-4a5e8ec41574c6b5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-707551df97d5eebd.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-e4df123bef1ff2b1.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-2fd6b0ff9b6741fc.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-3a829c53d5d723d2.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domain-records-0daa256958675a23.js → domain-records-92e8246170b492b5.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/locations-4194ce716b81480d.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/{organization-9404a6b0b2951992.js → organization-b235f961f9ca39a6.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/[id]/{test-datasets-48be14ad09ed4133.js → test-datasets-99cd1a12ae0373b0.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/systems/configure/{[id]-b03403fed4dd8805.js → [id]-01006a55ac873135.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{systems-ae591953b24e2fc9.js → systems-45990d85a4c5739b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-ec739e169cd5eafe.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/[id]-603c2bdbd8dc00ca.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management-592e497369673e1a.js +1 -0
- fides/ui-build/static/admin/_next/static/css/{c0c2eb63ad3e7390.css → 1b227ba7eabbfe2f.css} +1 -1
- fides/ui-build/static/admin/_next/static/css/5ded47c57dae5baf.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-ext-gpp.js +1 -1
- fides/ui-build/static/admin/lib/fides-headless.js +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/lib/fides.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 -0
- 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.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/service/error_handling/__init__.py +0 -0
- fides/service/error_handling/error_handler.py +0 -202
- fides/ui-build/static/admin/_next/static/4OMQ0x81J6D4ksHggHXOF/_buildManifest.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1327-92a38135ee8d55ec.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1817-721fdeb29c07c6be.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/1904-7e5354990377a849.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3119-e441b14cdab4320e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/3426-e49cb4766324b2dd.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/355-e4340980d72b4faa.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4060-9593a3f98e600487.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4121-5c3af879cdd8b3be.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4481-8398edf74aabb8ea.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/4723-4c3c7a375e998c15.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5258-e000d07844eccf7e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5626-1b636798faad78e1.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5683-44966a05fa5ad566.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5826-ce34f25ac2eeb807.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/5973-56d90405c3616068.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6277-c35c8cc806f7571f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/6853-0cee00c9da26a40e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/79-e5884e6878fc1bbb.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/7980-e17dda2f50ec76b8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/9767-74320abc2e9a4550.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/add-systems-a69f8946466471aa.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/configure-49b9f1b56262dfdc.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices-12f3ba4609bc2ba5.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/consent/reporting-b959d61c2a3682b3.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]/[systemId]-84ead584a88ab662.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center/[monitorId]-90f1975f559fff3e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-4b820a3173f35504.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset/new-1e26702b1a7e0e12.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/dataset-1f0c4e2e5d0b5bf6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection/new-c39e8e2269883796.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/datastore-connection-9db81467fa254996.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/[id]-ebc41649161f7fb9.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations-b89b9f68ccc69c1b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/[id]-928430cd40c35ef2.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/messaging-07ef58b04404479d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/configure/storage-595ed9f6ca438020.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-b3384299166bcd1e.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/reporting/datamap-6a6016708efb5f4f.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent/[configuration_id]/[purpose_id]-ba15c12c89ee10f8.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/consent-0f2daeec241bd1a2.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/custom-fields-0401208a3128fa4d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/settings/locations-4fbab6716326060d.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/taxonomy-913efe5371344de6.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management/profile/[id]-dc11ba29dbd4708b.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/user-management-c0b2113b44f46112.js +0 -1
- fides/ui-build/static/admin/_next/static/css/b89fc4b36b501cf6.css +0 -1
- {ethyca_fides-2.62.0rc0.dist-info → ethyca_fides-2.62.1b1.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.62.0rc0.dist-info → ethyca_fides-2.62.1b1.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.62.0rc0.dist-info → ethyca_fides-2.62.1b1.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{4OMQ0x81J6D4ksHggHXOF → Sez6kqW5dI0lK60IMwICO}/_ssgManifest.js +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{1099-98458e8e9ff67508.js → 1099-b652e6f9a0cd778b.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{1100-4106d99f5e1ebd75.js → 1100-e19e94b0a6486255.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{2921-ca04a0476e2e56c5.js → 2921-771dc5d9e95dc6b4.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{3505-e58b93f9c1cbdcad.js → 3505-313087fc1744a0ca.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{69-dc52e39d26a4ad14.js → 69-ef4c11c574b4e6dd.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{8433-a77c2cd1c1a6887e.js → 8433-755359b501d32eaa.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{8499-34a34015c91fc38b.js → 8499-06ab15acbfec037c.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{9327-a25347d72bfbe680.js → 9327-b691be8352e31b58.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{404-c00773c4c6e930af.js → 404-e868487119cd14fc.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-experience/{[id]-d4137bb7fdc1ac6e.js → [id]-94391554a7607c5b.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{[id]-a5a95ac63b1ce206.js → [id]-596dd2a35b455f21.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/consent/privacy-notices/{new-946ce1a2aa1500d4.js → new-fa7f0d2639e12a5a.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/{consent-7797e367dd946a18.js → consent-dd2a0e3b536b8b42.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{[id]-22812f08e81bd4f3.js → [id]-111b07344f1ee9e4.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/messaging/{add-template-ca22869201847ccc.js → add-template-c41f368fb6b35de4.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/poc/{ant-components-173bd3ad45ea61c6.js → ant-components-3dabaf6828acb2cb.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{AntForm-4dfe984ad80927cd.js → AntForm-784081c774042249.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikAntFormItem-f790e1ea5cbc26c0.js → FormikAntFormItem-63905f2382f158cd.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikControlled-af9e682ec620e990.js → FormikControlled-43f6eab28eae7b56.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/poc/form-experiments/{FormikField-6ce407101daa6000.js → FormikField-e4a07abc908fc9b5.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/poc/{forms-9ee8cf14a93eaa4a.js → forms-71a3bfb94280fc49.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests/{configure-25a3add8e7982e43.js → configure-42213855a0a8c209.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/properties/{[id]-081f13526443e0a6.js → [id]-d547a1da0b74f00f.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/properties/{add-property-17fb474e458b63e7.js → add-property-a7de6f8409a76358.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{about-177919b4ccf8f660.js → about-704fc28e61b17247.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{domains-26810d1ffedcd156.js → domains-f0e9ee8756a65540.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{email-templates-eb78b645d0c1d4ea.js → email-templates-a4771098466af1ed.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/settings/{regulations-0a3aa951ef4a44ba.js → regulations-8cff97fe57f42ed3.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/pages/user-management/{new-69176abe09cf9b52.js → new-b124cc24b930c9e1.js} +0 -0
- /fides/ui-build/static/admin/_next/static/chunks/{webpack-abd3efcb23c0bb03.js → webpack-3a61b934ba2fb620.js} +0 -0
fides/_version.py
CHANGED
@@ -8,11 +8,11 @@ import json
|
|
8
8
|
|
9
9
|
version_json = '''
|
10
10
|
{
|
11
|
-
"date": "2025-
|
11
|
+
"date": "2025-06-02T09:59:07-0700",
|
12
12
|
"dirty": false,
|
13
13
|
"error": null,
|
14
|
-
"full-revisionid": "
|
15
|
-
"version": "2.62.
|
14
|
+
"full-revisionid": "d7cf6cc495ac932a4b042e8249a4a49c8ae2070c",
|
15
|
+
"version": "2.62.1b1"
|
16
16
|
}
|
17
17
|
''' # END VERSION_JSON
|
18
18
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
"""add shared monitor config
|
2
|
+
|
3
|
+
Revision ID: 2263583b0e44
|
4
|
+
Revises: d0cbfec0b2dd
|
5
|
+
Create Date: 2025-05-12 23:44:11.809581
|
6
|
+
|
7
|
+
"""
|
8
|
+
|
9
|
+
import sqlalchemy as sa
|
10
|
+
from alembic import op
|
11
|
+
from sqlalchemy.dialects import postgresql
|
12
|
+
|
13
|
+
# revision identifiers, used by Alembic.
|
14
|
+
revision = "2263583b0e44"
|
15
|
+
down_revision = "d0cbfec0b2dd"
|
16
|
+
branch_labels = None
|
17
|
+
depends_on = None
|
18
|
+
|
19
|
+
|
20
|
+
def upgrade():
|
21
|
+
op.create_table(
|
22
|
+
"shared_monitor_config",
|
23
|
+
sa.Column("id", sa.String(length=255), nullable=False),
|
24
|
+
sa.Column(
|
25
|
+
"created_at",
|
26
|
+
sa.DateTime(timezone=True),
|
27
|
+
server_default=sa.text("now()"),
|
28
|
+
nullable=True,
|
29
|
+
),
|
30
|
+
sa.Column(
|
31
|
+
"updated_at",
|
32
|
+
sa.DateTime(timezone=True),
|
33
|
+
server_default=sa.text("now()"),
|
34
|
+
nullable=True,
|
35
|
+
),
|
36
|
+
sa.Column("name", sa.String(), nullable=False),
|
37
|
+
sa.Column("key", sa.String(), nullable=False),
|
38
|
+
sa.Column("description", sa.String(), nullable=True),
|
39
|
+
sa.Column(
|
40
|
+
"classify_params",
|
41
|
+
postgresql.JSONB(astext_type=sa.Text()),
|
42
|
+
server_default="{}",
|
43
|
+
nullable=False,
|
44
|
+
),
|
45
|
+
sa.PrimaryKeyConstraint("id"),
|
46
|
+
sa.UniqueConstraint("key"),
|
47
|
+
)
|
48
|
+
op.create_index(
|
49
|
+
op.f("ix_shared_monitor_config_id"),
|
50
|
+
"shared_monitor_config",
|
51
|
+
["id"],
|
52
|
+
unique=False,
|
53
|
+
)
|
54
|
+
op.add_column(
|
55
|
+
"monitorconfig", sa.Column("shared_config_id", sa.String(), nullable=True)
|
56
|
+
)
|
57
|
+
op.create_index(
|
58
|
+
op.f("ix_monitorconfig_shared_config_id"),
|
59
|
+
"monitorconfig",
|
60
|
+
["shared_config_id"],
|
61
|
+
unique=False,
|
62
|
+
)
|
63
|
+
op.create_foreign_key(
|
64
|
+
"fk_monitorconfig_shared_config_id",
|
65
|
+
"monitorconfig",
|
66
|
+
"shared_monitor_config",
|
67
|
+
["shared_config_id"],
|
68
|
+
["id"],
|
69
|
+
ondelete="RESTRICT",
|
70
|
+
)
|
71
|
+
|
72
|
+
|
73
|
+
def downgrade():
|
74
|
+
op.drop_constraint(
|
75
|
+
"fk_monitorconfig_shared_config_id", "monitorconfig", type_="foreignkey"
|
76
|
+
)
|
77
|
+
op.drop_index(op.f("ix_monitorconfig_shared_config_id"), table_name="monitorconfig")
|
78
|
+
op.drop_column("monitorconfig", "shared_config_id")
|
79
|
+
op.drop_index(
|
80
|
+
op.f("ix_shared_monitor_config_id"), table_name="shared_monitor_config"
|
81
|
+
)
|
82
|
+
op.drop_table("shared_monitor_config")
|
@@ -120,7 +120,7 @@ from fides.api.util.collection_util import Row
|
|
120
120
|
from fides.api.util.endpoint_utils import validate_start_and_end_filters
|
121
121
|
from fides.api.util.enums import ColumnSort
|
122
122
|
from fides.api.util.fuzzy_search_utils import get_decrypted_identities_automaton
|
123
|
-
from fides.api.util.storage_util import
|
123
|
+
from fides.api.util.storage_util import StorageJSONEncoder
|
124
124
|
from fides.common.api.scope_registry import (
|
125
125
|
PRIVACY_REQUEST_CALLBACK_RESUME,
|
126
126
|
PRIVACY_REQUEST_CREATE,
|
@@ -2129,7 +2129,7 @@ def get_test_privacy_request_results(
|
|
2129
2129
|
|
2130
2130
|
# Escape datetime and ObjectId values
|
2131
2131
|
raw_data = privacy_request.get_raw_access_results()
|
2132
|
-
escaped_json = json.dumps(raw_data, indent=2,
|
2132
|
+
escaped_json = json.dumps(raw_data, indent=2, cls=StorageJSONEncoder)
|
2133
2133
|
results = json.loads(escaped_json)
|
2134
2134
|
|
2135
2135
|
filtered_results: Dict[str, Any] = filter_access_results(
|
fides/api/models/attachment.py
CHANGED
@@ -12,12 +12,14 @@ from sqlalchemy.orm import Session, relationship
|
|
12
12
|
|
13
13
|
from fides.api.db.base_class import Base
|
14
14
|
from fides.api.schemas.storage.storage import StorageDetails, StorageType
|
15
|
+
from fides.api.service.storage.gcs import get_gcs_client
|
15
16
|
from fides.api.service.storage.s3 import (
|
16
17
|
generic_delete_from_s3,
|
17
18
|
generic_retrieve_from_s3,
|
18
19
|
generic_upload_to_s3,
|
19
20
|
)
|
20
|
-
from fides.api.service.storage.util import get_local_filename
|
21
|
+
from fides.api.service.storage.util import AllowedFileType, get_local_filename
|
22
|
+
from fides.config import CONFIG
|
21
23
|
|
22
24
|
if TYPE_CHECKING:
|
23
25
|
from fides.api.models.comment import Comment
|
@@ -115,8 +117,13 @@ class Attachment(Base):
|
|
115
117
|
uselist=False,
|
116
118
|
)
|
117
119
|
|
120
|
+
@property
|
121
|
+
def content_type(self) -> str:
|
122
|
+
"""Returns the content type of the attachment."""
|
123
|
+
return AllowedFileType[self.file_name.split(".")[-1]].value
|
124
|
+
|
118
125
|
def upload(self, attachment: IO[bytes]) -> None:
|
119
|
-
"""Uploads an attachment to S3 or local storage."""
|
126
|
+
"""Uploads an attachment to S3, GCS, or local storage."""
|
120
127
|
if self.config.type == StorageType.s3:
|
121
128
|
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
122
129
|
auth_method = self.config.details[StorageDetails.AUTH_METHOD.value]
|
@@ -130,6 +137,23 @@ class Attachment(Base):
|
|
130
137
|
log.info(f"Uploaded {self.file_name} to S3 bucket {bucket_name}/{self.id}")
|
131
138
|
return
|
132
139
|
|
140
|
+
if self.config.type == StorageType.gcs:
|
141
|
+
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
142
|
+
auth_method = self.config.details[StorageDetails.AUTH_METHOD.value]
|
143
|
+
storage_client = get_gcs_client(auth_method, self.config.secrets)
|
144
|
+
bucket = storage_client.bucket(bucket_name)
|
145
|
+
blob = bucket.blob(f"{self.id}/{self.file_name}")
|
146
|
+
|
147
|
+
# Reset the file pointer to the beginning
|
148
|
+
try:
|
149
|
+
attachment.seek(0)
|
150
|
+
except Exception as e:
|
151
|
+
raise ValueError(f"Failed to reset file pointer for attachment: {e}")
|
152
|
+
|
153
|
+
blob.upload_from_file(attachment)
|
154
|
+
log.info(f"Uploaded {self.file_name} to GCS bucket {bucket_name}/{self.id}")
|
155
|
+
return
|
156
|
+
|
133
157
|
if self.config.type == StorageType.local:
|
134
158
|
filename = get_local_filename(f"{self.id}/{self.file_name}")
|
135
159
|
|
@@ -164,13 +188,16 @@ class Attachment(Base):
|
|
164
188
|
self,
|
165
189
|
) -> Tuple[int, AnyHttpUrlString]:
|
166
190
|
"""
|
167
|
-
Retrieves
|
191
|
+
Retrieves the size of the attachment and a presigned/signed URL.
|
168
192
|
- For s3:
|
169
193
|
- the size is retrieved from the s3 object metadata
|
170
|
-
-
|
194
|
+
- returns presigned URL
|
195
|
+
- For gcs:
|
196
|
+
- the size is retrieved from the blob metadata
|
197
|
+
- returns signed URL
|
171
198
|
- For local:
|
172
199
|
- the size is retrieved from the file size
|
173
|
-
-
|
200
|
+
- returns the local file path
|
174
201
|
"""
|
175
202
|
if self.config.type == StorageType.s3:
|
176
203
|
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
@@ -180,19 +207,81 @@ class Attachment(Base):
|
|
180
207
|
bucket_name=bucket_name,
|
181
208
|
file_key=f"{self.id}/{self.file_name}",
|
182
209
|
auth_method=auth_method,
|
210
|
+
get_content=False,
|
183
211
|
)
|
184
212
|
return size, url
|
185
213
|
|
214
|
+
if self.config.type == StorageType.gcs:
|
215
|
+
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
216
|
+
auth_method = self.config.details[StorageDetails.AUTH_METHOD.value]
|
217
|
+
storage_client = get_gcs_client(auth_method, self.config.secrets)
|
218
|
+
bucket = storage_client.bucket(bucket_name)
|
219
|
+
blob = bucket.blob(f"{self.id}/{self.file_name}")
|
220
|
+
|
221
|
+
# Ensure we have the blob metadata
|
222
|
+
blob.reload()
|
223
|
+
url = blob.generate_signed_url(
|
224
|
+
version="v4",
|
225
|
+
expiration=CONFIG.security.subject_request_download_link_ttl_seconds,
|
226
|
+
method="GET",
|
227
|
+
)
|
228
|
+
return blob.size, url
|
229
|
+
|
230
|
+
if self.config.type == StorageType.local:
|
231
|
+
filename = get_local_filename(f"{self.id}/{self.file_name}")
|
232
|
+
size = os.path.getsize(filename)
|
233
|
+
return size, filename
|
234
|
+
|
235
|
+
raise ValueError(f"Unsupported storage type: {self.config.type}")
|
236
|
+
|
237
|
+
def retrieve_attachment_content(
|
238
|
+
self,
|
239
|
+
) -> Tuple[int, bytes]:
|
240
|
+
"""
|
241
|
+
Retrieves the size of the attachment and its actual content.
|
242
|
+
- For s3:
|
243
|
+
- the size is retrieved from the s3 object metadata
|
244
|
+
- returns the actual content
|
245
|
+
- For gcs:
|
246
|
+
- the size is retrieved from the blob metadata
|
247
|
+
- returns the actual content
|
248
|
+
- For local:
|
249
|
+
- the size is retrieved from the file size
|
250
|
+
- returns the actual content
|
251
|
+
"""
|
252
|
+
if self.config.type == StorageType.s3:
|
253
|
+
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
254
|
+
auth_method = self.config.details[StorageDetails.AUTH_METHOD.value]
|
255
|
+
size, content = generic_retrieve_from_s3(
|
256
|
+
storage_secrets=self.config.secrets,
|
257
|
+
bucket_name=bucket_name,
|
258
|
+
file_key=f"{self.id}/{self.file_name}",
|
259
|
+
auth_method=auth_method,
|
260
|
+
get_content=True,
|
261
|
+
)
|
262
|
+
return size, content
|
263
|
+
|
264
|
+
if self.config.type == StorageType.gcs:
|
265
|
+
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
266
|
+
auth_method = self.config.details[StorageDetails.AUTH_METHOD.value]
|
267
|
+
storage_client = get_gcs_client(auth_method, self.config.secrets)
|
268
|
+
bucket = storage_client.bucket(bucket_name)
|
269
|
+
blob = bucket.blob(f"{self.id}/{self.file_name}")
|
270
|
+
|
271
|
+
content = blob.download_as_bytes()
|
272
|
+
return len(content), content
|
273
|
+
|
186
274
|
if self.config.type == StorageType.local:
|
187
275
|
filename = get_local_filename(f"{self.id}/{self.file_name}")
|
188
276
|
with open(filename, "rb") as file:
|
189
|
-
|
190
|
-
|
277
|
+
content = file.read()
|
278
|
+
size = len(content)
|
279
|
+
return size, content
|
191
280
|
|
192
281
|
raise ValueError(f"Unsupported storage type: {self.config.type}")
|
193
282
|
|
194
283
|
def delete_attachment_from_storage(self) -> None:
|
195
|
-
"""Deletes an attachment from S3 or local storage."""
|
284
|
+
"""Deletes an attachment from S3, GCS, or local storage."""
|
196
285
|
if self.config.type == StorageType.s3:
|
197
286
|
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
198
287
|
auth_method = self.config.details[StorageDetails.AUTH_METHOD.value]
|
@@ -204,9 +293,27 @@ class Attachment(Base):
|
|
204
293
|
)
|
205
294
|
return
|
206
295
|
|
296
|
+
if self.config.type == StorageType.gcs:
|
297
|
+
bucket_name = f"{self.config.details[StorageDetails.BUCKET.value]}"
|
298
|
+
auth_method = self.config.details[StorageDetails.AUTH_METHOD.value]
|
299
|
+
storage_client = get_gcs_client(auth_method, self.config.secrets)
|
300
|
+
bucket = storage_client.bucket(bucket_name)
|
301
|
+
|
302
|
+
# List and delete all blobs in the folder
|
303
|
+
prefix = f"{self.id}/"
|
304
|
+
blobs = bucket.list_blobs(prefix=prefix)
|
305
|
+
for blob in blobs:
|
306
|
+
blob.delete()
|
307
|
+
return
|
308
|
+
|
207
309
|
if self.config.type == StorageType.local:
|
208
|
-
|
209
|
-
|
310
|
+
folder_path = os.path.dirname(
|
311
|
+
get_local_filename(f"{self.id}/{self.file_name}")
|
312
|
+
)
|
313
|
+
if os.path.exists(folder_path):
|
314
|
+
import shutil
|
315
|
+
|
316
|
+
shutil.rmtree(folder_path)
|
210
317
|
return
|
211
318
|
|
212
319
|
raise ValueError(f"Unsupported storage type: {self.config.type}")
|
@@ -9,6 +9,7 @@ from loguru import logger
|
|
9
9
|
from sqlalchemy import ARRAY, Boolean, Column, DateTime, ForeignKey, String, func
|
10
10
|
from sqlalchemy.dialects.postgresql import JSONB
|
11
11
|
from sqlalchemy.ext.asyncio import AsyncSession
|
12
|
+
from sqlalchemy.ext.declarative import declared_attr
|
12
13
|
from sqlalchemy.ext.mutable import MutableDict
|
13
14
|
from sqlalchemy.future import select
|
14
15
|
from sqlalchemy.orm import Session, relationship
|
@@ -47,6 +48,29 @@ class MonitorFrequency(Enum):
|
|
47
48
|
QUARTERLY_MONTH_PATTERN = r"^\d+,\d+,\d+,\d+$"
|
48
49
|
|
49
50
|
|
51
|
+
class SharedMonitorConfig(Base, FidesBase):
|
52
|
+
"""SQL model for shareable monitor configurations"""
|
53
|
+
|
54
|
+
@declared_attr
|
55
|
+
def __tablename__(self) -> str:
|
56
|
+
return "shared_monitor_config"
|
57
|
+
|
58
|
+
# Basic info
|
59
|
+
name = Column(String, nullable=False)
|
60
|
+
key = Column(String, unique=True, nullable=False)
|
61
|
+
description = Column(String, nullable=True)
|
62
|
+
|
63
|
+
# Classification parameters (including regex patterns)
|
64
|
+
classify_params = Column(
|
65
|
+
MutableDict.as_mutable(JSONB),
|
66
|
+
index=False,
|
67
|
+
unique=False,
|
68
|
+
nullable=False,
|
69
|
+
server_default="{}",
|
70
|
+
default=dict,
|
71
|
+
)
|
72
|
+
|
73
|
+
|
50
74
|
class MonitorConfig(Base):
|
51
75
|
"""
|
52
76
|
Monitor configuration used for data detection and discovery.
|
@@ -87,7 +111,9 @@ class MonitorConfig(Base):
|
|
87
111
|
) # stores the cron-based kwargs for scheduling the monitor execution.
|
88
112
|
# see https://apscheduler.readthedocs.io/en/3.x/modules/triggers/cron.html
|
89
113
|
|
90
|
-
|
114
|
+
# We use _classify_params for the actual column to prevent direct access
|
115
|
+
_classify_params = Column(
|
116
|
+
"classify_params",
|
91
117
|
MutableDict.as_mutable(JSONB),
|
92
118
|
index=False,
|
93
119
|
unique=False,
|
@@ -124,6 +150,45 @@ class MonitorConfig(Base):
|
|
124
150
|
backref="monitor_config",
|
125
151
|
)
|
126
152
|
|
153
|
+
shared_config_id = Column(
|
154
|
+
String,
|
155
|
+
ForeignKey(SharedMonitorConfig.id_field_path, ondelete="RESTRICT"),
|
156
|
+
nullable=True,
|
157
|
+
index=True,
|
158
|
+
)
|
159
|
+
|
160
|
+
shared_config = relationship(SharedMonitorConfig)
|
161
|
+
|
162
|
+
@property
|
163
|
+
def classify_params(self) -> dict:
|
164
|
+
"""
|
165
|
+
Returns the merged classify parameters from both the monitor config and
|
166
|
+
the shared config (if it exists).
|
167
|
+
|
168
|
+
The shared config parameters take precedence over the monitor's own parameters,
|
169
|
+
but only for values that are not falsy (None, empty, etc.).
|
170
|
+
"""
|
171
|
+
# Start with an empty dict
|
172
|
+
merged_params = {}
|
173
|
+
|
174
|
+
# Add this monitor's params if available
|
175
|
+
if self._classify_params:
|
176
|
+
merged_params.update(self._classify_params)
|
177
|
+
|
178
|
+
# Add/override with shared config params if available
|
179
|
+
if self.shared_config and self.shared_config.classify_params:
|
180
|
+
# Only update with non-falsy values from shared config
|
181
|
+
for key, value in self.shared_config.classify_params.items():
|
182
|
+
if value: # Only override if the value is not falsy
|
183
|
+
merged_params[key] = value
|
184
|
+
|
185
|
+
return merged_params
|
186
|
+
|
187
|
+
@classify_params.setter
|
188
|
+
def classify_params(self, value: Dict[str, Any]) -> None:
|
189
|
+
"""Setter for the classify_params to maintain compatibility with existing code"""
|
190
|
+
self._classify_params = value
|
191
|
+
|
127
192
|
@property
|
128
193
|
def connection_config_key(self) -> str:
|
129
194
|
"""Derives the `connection_config_key`"""
|
@@ -1089,6 +1089,46 @@ class PrivacyRequest(
|
|
1089
1089
|
if attachment:
|
1090
1090
|
attachment.delete(db)
|
1091
1091
|
|
1092
|
+
def _get_manual_webhook_attachments(
|
1093
|
+
self, db: Session, manual_webhook_id: str, reference_type: str
|
1094
|
+
) -> List[Attachment]:
|
1095
|
+
"""Helper method to get attachments that have references to both this privacy request and the specified manual webhook"""
|
1096
|
+
query = """
|
1097
|
+
SELECT DISTINCT a.*
|
1098
|
+
FROM attachment a
|
1099
|
+
INNER JOIN attachment_reference ar1 ON a.id = ar1.attachment_id
|
1100
|
+
INNER JOIN attachment_reference ar2 ON a.id = ar2.attachment_id
|
1101
|
+
WHERE ar1.reference_id = :privacy_request_id
|
1102
|
+
AND ar1.reference_type = 'privacy_request'
|
1103
|
+
AND ar2.reference_id = :manual_webhook_id
|
1104
|
+
AND ar2.reference_type = :reference_type
|
1105
|
+
"""
|
1106
|
+
result = db.execute(
|
1107
|
+
query,
|
1108
|
+
{
|
1109
|
+
"privacy_request_id": self.id,
|
1110
|
+
"manual_webhook_id": manual_webhook_id,
|
1111
|
+
"reference_type": reference_type,
|
1112
|
+
},
|
1113
|
+
)
|
1114
|
+
return [Attachment(**row) for row in result]
|
1115
|
+
|
1116
|
+
def get_access_manual_webhook_attachments(
|
1117
|
+
self, db: Session, manual_webhook_id: str
|
1118
|
+
) -> List[Attachment]:
|
1119
|
+
"""Get all attachments that have references to both this privacy request and the specified access manual webhook"""
|
1120
|
+
return self._get_manual_webhook_attachments(
|
1121
|
+
db, manual_webhook_id, "access_manual_webhook"
|
1122
|
+
)
|
1123
|
+
|
1124
|
+
def get_erasure_manual_webhook_attachments(
|
1125
|
+
self, db: Session, manual_webhook_id: str
|
1126
|
+
) -> List[Attachment]:
|
1127
|
+
"""Get all attachments that have references to both this privacy request and the specified erasure manual webhook"""
|
1128
|
+
return self._get_manual_webhook_attachments(
|
1129
|
+
db, manual_webhook_id, "erasure_manual_webhook"
|
1130
|
+
)
|
1131
|
+
|
1092
1132
|
def get_existing_request_task(
|
1093
1133
|
self,
|
1094
1134
|
db: Session,
|
@@ -1228,7 +1268,6 @@ class PrivacyRequest(
|
|
1228
1268
|
"""
|
1229
1269
|
if not self.policy.get_rules_for_action(action_type=ActionType.access):
|
1230
1270
|
return None
|
1231
|
-
|
1232
1271
|
self.filtered_final_upload = results
|
1233
1272
|
self.save(db)
|
1234
1273
|
|
@@ -11,7 +11,7 @@ from jinja2 import Environment, FileSystemLoader
|
|
11
11
|
|
12
12
|
from fides.api.models.privacy_request import PrivacyRequest
|
13
13
|
from fides.api.schemas.policy import ActionType
|
14
|
-
from fides.api.util.storage_util import
|
14
|
+
from fides.api.util.storage_util import StorageJSONEncoder
|
15
15
|
|
16
16
|
DSR_DIRECTORY = Path(__file__).parent.resolve()
|
17
17
|
|
@@ -41,7 +41,9 @@ class DsrReportBuilder:
|
|
41
41
|
|
42
42
|
# Jinja template environment initialization
|
43
43
|
def pretty_print(value: str, indent: int = 4) -> str:
|
44
|
-
return json.dumps(
|
44
|
+
return json.dumps(
|
45
|
+
value, indent=indent, default=StorageJSONEncoder().default
|
46
|
+
)
|
45
47
|
|
46
48
|
jinja2.filters.FILTERS["pretty_print"] = pretty_print
|
47
49
|
self.template_loader = Environment(
|
fides/api/service/storage/s3.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
from __future__ import annotations
|
2
2
|
|
3
|
-
from typing import IO, Any, Dict, Tuple
|
3
|
+
from typing import IO, Any, Dict, Tuple, Union
|
4
4
|
|
5
5
|
from boto3.s3.transfer import TransferConfig
|
6
6
|
from botocore.exceptions import ClientError, ParamValidationError
|
@@ -129,25 +129,38 @@ def generic_retrieve_from_s3(
|
|
129
129
|
bucket_name: str,
|
130
130
|
file_key: str,
|
131
131
|
auth_method: str,
|
132
|
-
|
132
|
+
get_content: bool = False,
|
133
|
+
) -> Tuple[int, Union[str, bytes]]:
|
133
134
|
"""
|
134
|
-
Retrieves file
|
135
|
+
Retrieves a file from S3 and returns its size and either a presigned URL or the actual content.
|
135
136
|
|
136
|
-
:
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
137
|
+
Args:
|
138
|
+
storage_secrets: Dictionary containing S3 credentials
|
139
|
+
bucket_name: Name of the S3 bucket
|
140
|
+
file_key: Key of the file in the bucket
|
141
|
+
auth_method: Authentication method to use
|
142
|
+
get_content: If True, returns the actual content instead of a presigned URL
|
143
|
+
|
144
|
+
Returns:
|
145
|
+
Tuple containing (file_size, presigned_url_or_content)
|
141
146
|
"""
|
142
147
|
logger.info("Retrieving S3 object: {}", file_key)
|
148
|
+
s3_client = get_s3_client(auth_method, storage_secrets)
|
143
149
|
|
144
|
-
s3_client = maybe_get_s3_client(auth_method, storage_secrets)
|
145
150
|
try:
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
+
if get_content:
|
152
|
+
# Get the actual content
|
153
|
+
response = s3_client.get_object(Bucket=bucket_name, Key=file_key)
|
154
|
+
content = response["Body"].read()
|
155
|
+
return response["ContentLength"], content
|
156
|
+
|
157
|
+
# Get presigned URL
|
158
|
+
presigned_url = create_presigned_url_for_s3(s3_client, bucket_name, file_key)
|
159
|
+
# Get file size
|
160
|
+
response = s3_client.head_object(Bucket=bucket_name, Key=file_key)
|
161
|
+
return int(response["ContentLength"]), str(presigned_url)
|
162
|
+
except ClientError as e:
|
163
|
+
logger.error(f"Error retrieving file from S3: {e}")
|
151
164
|
raise e
|
152
165
|
|
153
166
|
|
@@ -158,7 +171,8 @@ def generic_delete_from_s3(
|
|
158
171
|
auth_method: str,
|
159
172
|
) -> None:
|
160
173
|
"""
|
161
|
-
Deletes arbitrary data from s3
|
174
|
+
Deletes arbitrary data from s3. If file_key ends with a filename, deletes just that file.
|
175
|
+
If file_key ends with a '/', deletes all objects with that prefix.
|
162
176
|
|
163
177
|
:param storage_secrets: S3 storage secrets
|
164
178
|
:param bucket_name: Name of the S3 bucket
|
@@ -169,6 +183,17 @@ def generic_delete_from_s3(
|
|
169
183
|
|
170
184
|
s3_client = maybe_get_s3_client(auth_method, storage_secrets)
|
171
185
|
try:
|
186
|
+
# If the file_key ends with a '/', it's a folder prefix
|
187
|
+
if file_key.endswith("/"):
|
188
|
+
# List all objects with the prefix, handling pagination
|
189
|
+
paginator = s3_client.get_paginator("list_objects_v2")
|
190
|
+
for page in paginator.paginate(Bucket=bucket_name, Prefix=file_key):
|
191
|
+
if "Contents" in page:
|
192
|
+
for obj in page["Contents"]:
|
193
|
+
s3_client.delete_object(Bucket=bucket_name, Key=obj["Key"])
|
194
|
+
return
|
195
|
+
|
196
|
+
# Delete single object
|
172
197
|
s3_client.delete_object(Bucket=bucket_name, Key=file_key)
|
173
198
|
except Exception as e:
|
174
199
|
logger.error("Encountered error while deleting s3 object: {}", e)
|
fides/api/tasks/storage.py
CHANGED
@@ -30,7 +30,7 @@ from fides.api.util.cache import get_cache, get_encryption_cache_key
|
|
30
30
|
from fides.api.util.encryption.aes_gcm_encryption_scheme import (
|
31
31
|
encrypt_to_bytes_verify_secrets_length,
|
32
32
|
)
|
33
|
-
from fides.api.util.storage_util import
|
33
|
+
from fides.api.util.storage_util import StorageJSONEncoder
|
34
34
|
from fides.config import CONFIG
|
35
35
|
|
36
36
|
if TYPE_CHECKING:
|
@@ -75,7 +75,7 @@ def write_to_in_memory_buffer(
|
|
75
75
|
logger.debug("Writing data to in-memory buffer")
|
76
76
|
|
77
77
|
if resp_format == ResponseFormat.json.value:
|
78
|
-
json_str = json.dumps(data, indent=2, default=
|
78
|
+
json_str = json.dumps(data, indent=2, default=StorageJSONEncoder().default)
|
79
79
|
return BytesIO(
|
80
80
|
encrypt_access_request_results(json_str, privacy_request.id).encode(
|
81
81
|
CONFIG.security.encoding
|
fides/api/util/storage_util.py
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
from datetime import datetime
|
2
|
-
from typing import Any,
|
2
|
+
from typing import Any, Union
|
3
3
|
|
4
4
|
from bson import ObjectId
|
5
5
|
from pydantic import ValidationError
|
@@ -11,6 +11,7 @@ from fides.api.schemas.storage.storage import (
|
|
11
11
|
StorageType,
|
12
12
|
)
|
13
13
|
from fides.api.schemas.storage.storage_secrets_docs_only import possible_storage_secrets
|
14
|
+
from fides.api.util.custom_json_encoder import CustomJSONEncoder
|
14
15
|
|
15
16
|
|
16
17
|
def get_schema_for_secrets(
|
@@ -48,10 +49,15 @@ def get_schema_for_secrets(
|
|
48
49
|
raise ValueError(errors)
|
49
50
|
|
50
51
|
|
51
|
-
|
52
|
-
"""
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
52
|
+
class StorageJSONEncoder(CustomJSONEncoder):
|
53
|
+
"""
|
54
|
+
A JSON encoder specifically for storage operations that maintains the original
|
55
|
+
format for datetime and ObjectId while inheriting other functionality from CustomJSONEncoder.
|
56
|
+
"""
|
57
|
+
|
58
|
+
def default(self, o: Any) -> Any:
|
59
|
+
if isinstance(o, datetime):
|
60
|
+
return o.strftime("%Y-%m-%dT%H:%M:%S")
|
61
|
+
if isinstance(o, ObjectId):
|
62
|
+
return {"$oid": str(o)}
|
63
|
+
return super().default(o)
|
@@ -1 +1 @@
|
|
1
|
-
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/
|
1
|
+
<!DOCTYPE html><html lang="en"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width"/><meta name="next-head-count" content="2"/><link data-next-font="" rel="preconnect" href="/" crossorigin="anonymous"/><link rel="preload" href="/_next/static/css/1b227ba7eabbfe2f.css" as="style"/><link rel="stylesheet" href="/_next/static/css/1b227ba7eabbfe2f.css" data-n-g=""/><noscript data-n-css=""></noscript><script defer="" nomodule="" src="/_next/static/chunks/polyfills-42372ed130431b0a.js"></script><script src="/_next/static/chunks/webpack-3a61b934ba2fb620.js" defer=""></script><script src="/_next/static/chunks/framework-c92fc3344e6fd165.js" defer=""></script><script src="/_next/static/chunks/main-090643377c8254e6.js" defer=""></script><script src="/_next/static/chunks/pages/_app-94950df9c97cd079.js" defer=""></script><script src="/_next/static/chunks/pages/404-e868487119cd14fc.js" defer=""></script><script src="/_next/static/Sez6kqW5dI0lK60IMwICO/_buildManifest.js" defer=""></script><script src="/_next/static/Sez6kqW5dI0lK60IMwICO/_ssgManifest.js" defer=""></script><style>.data-ant-cssinjs-cache-path{content:"";}</style></head><body><div id="__next"><div style="height:100%;display:flex"></div></div><script id="__NEXT_DATA__" type="application/json">{"props":{"pageProps":{}},"page":"/404","query":{},"buildId":"Sez6kqW5dI0lK60IMwICO","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|