ethyca-fides 2.68.1b1__py2.py3-none-any.whl → 2.68.1b2__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.1b1.dist-info → ethyca_fides-2.68.1b2.dist-info}/METADATA +1 -1
- {ethyca_fides-2.68.1b1.dist-info → ethyca_fides-2.68.1b2.dist-info}/RECORD +113 -105
- fides/_version.py +3 -3
- fides/api/alembic/migrations/versions/3baf42d251a6_add_generic_taxonomy_models.py +239 -0
- fides/api/api/v1/endpoints/generic_overrides.py +64 -167
- fides/api/db/base.py +6 -0
- fides/api/models/taxonomy.py +275 -0
- fides/api/service/deps.py +5 -0
- fides/api/service/privacy_request/request_service.py +6 -1
- fides/api/task/manual/manual_task_graph_task.py +11 -0
- fides/api/util/connection_type.py +68 -33
- fides/data/sample_project/docker-compose.yml +3 -3
- fides/service/taxonomy/__init__.py +0 -0
- fides/service/taxonomy/handlers/__init__.py +11 -0
- fides/service/taxonomy/handlers/base.py +42 -0
- fides/service/taxonomy/handlers/legacy_handler.py +95 -0
- fides/service/taxonomy/taxonomy_service.py +261 -0
- fides/service/taxonomy/utils.py +160 -0
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-65723cd4b8fc36ac.js → _app-2c10f6b217b7978b.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/data-discovery/action-center-58827eb86516931f.js +1 -0
- fides/ui-build/static/admin/_next/static/chunks/pages/integrations/{[id]-766e57bcf38b5b1e.js → [id]-4e286a1e501a0c73.js} +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-709bcb0bc6a5382d.js +1 -0
- fides/ui-build/static/admin/_next/static/css/a72179b1754aadd3.css +1 -0
- fides/ui-build/static/admin/_next/static/{tzF4yti8NslASlGnxnZ8m → qvk5eMANVfwYkdURE7fgG}/_buildManifest.js +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/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 +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/pages/data-discovery/action-center-53a763e49ce34a74.js +0 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/privacy-requests-f43a988542813110.js +0 -1
- fides/ui-build/static/admin/_next/static/css/e1628f15dd5f019b.css +0 -1
- {ethyca_fides-2.68.1b1.dist-info → ethyca_fides-2.68.1b2.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.68.1b1.dist-info → ethyca_fides-2.68.1b2.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.68.1b1.dist-info → ethyca_fides-2.68.1b2.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.68.1b1.dist-info → ethyca_fides-2.68.1b2.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{tzF4yti8NslASlGnxnZ8m → qvk5eMANVfwYkdURE7fgG}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
"""add generic taxonomy models
|
|
2
|
+
|
|
3
|
+
Revision ID: 3baf42d251a6
|
|
4
|
+
Revises: 2f3c1a2d6b10
|
|
5
|
+
Create Date: 2025-08-05 21:49:39.619569
|
|
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 = "3baf42d251a6"
|
|
15
|
+
down_revision = "2f3c1a2d6b10"
|
|
16
|
+
branch_labels = None
|
|
17
|
+
depends_on = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def upgrade():
|
|
21
|
+
# Create taxonomy table
|
|
22
|
+
op.create_table(
|
|
23
|
+
"taxonomy",
|
|
24
|
+
sa.Column("id", sa.String(length=255), nullable=False),
|
|
25
|
+
sa.Column(
|
|
26
|
+
"created_at",
|
|
27
|
+
sa.DateTime(timezone=True),
|
|
28
|
+
server_default=sa.text("now()"),
|
|
29
|
+
nullable=True,
|
|
30
|
+
),
|
|
31
|
+
sa.Column(
|
|
32
|
+
"updated_at",
|
|
33
|
+
sa.DateTime(timezone=True),
|
|
34
|
+
server_default=sa.text("now()"),
|
|
35
|
+
nullable=True,
|
|
36
|
+
),
|
|
37
|
+
sa.Column("fides_key", sa.String(), nullable=False),
|
|
38
|
+
sa.Column("organization_fides_key", sa.Text(), nullable=True),
|
|
39
|
+
sa.Column("tags", postgresql.ARRAY(sa.String()), nullable=True),
|
|
40
|
+
sa.Column("name", sa.Text(), nullable=True),
|
|
41
|
+
sa.Column("description", sa.Text(), nullable=True),
|
|
42
|
+
sa.PrimaryKeyConstraint("fides_key"),
|
|
43
|
+
sa.UniqueConstraint("id", name="uq_taxonomy_id"),
|
|
44
|
+
)
|
|
45
|
+
op.create_index(
|
|
46
|
+
op.f("ix_taxonomy_fides_key"), "taxonomy", ["fides_key"], unique=True
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
# Create taxonomy_allowed_usage table
|
|
50
|
+
op.create_table(
|
|
51
|
+
"taxonomy_allowed_usage",
|
|
52
|
+
sa.Column("id", sa.String(length=255), nullable=False),
|
|
53
|
+
sa.Column(
|
|
54
|
+
"created_at",
|
|
55
|
+
sa.DateTime(timezone=True),
|
|
56
|
+
server_default=sa.text("now()"),
|
|
57
|
+
nullable=True,
|
|
58
|
+
),
|
|
59
|
+
sa.Column(
|
|
60
|
+
"updated_at",
|
|
61
|
+
sa.DateTime(timezone=True),
|
|
62
|
+
server_default=sa.text("now()"),
|
|
63
|
+
nullable=True,
|
|
64
|
+
),
|
|
65
|
+
sa.Column("source_taxonomy_key", sa.String(), nullable=False),
|
|
66
|
+
sa.Column(
|
|
67
|
+
"target_type", sa.String(), nullable=False
|
|
68
|
+
), # Can be "system" OR "data_categories"
|
|
69
|
+
sa.ForeignKeyConstraint(
|
|
70
|
+
["source_taxonomy_key"], ["taxonomy.fides_key"], ondelete="CASCADE"
|
|
71
|
+
),
|
|
72
|
+
sa.PrimaryKeyConstraint("source_taxonomy_key", "target_type"),
|
|
73
|
+
sa.UniqueConstraint("id", name="uq_taxonomy_allowed_usage_id"),
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Create taxonomy_element table
|
|
77
|
+
op.create_table(
|
|
78
|
+
"taxonomy_element",
|
|
79
|
+
sa.Column("id", sa.String(length=255), nullable=False),
|
|
80
|
+
sa.Column(
|
|
81
|
+
"created_at",
|
|
82
|
+
sa.DateTime(timezone=True),
|
|
83
|
+
server_default=sa.text("now()"),
|
|
84
|
+
nullable=True,
|
|
85
|
+
),
|
|
86
|
+
sa.Column(
|
|
87
|
+
"updated_at",
|
|
88
|
+
sa.DateTime(timezone=True),
|
|
89
|
+
server_default=sa.text("now()"),
|
|
90
|
+
nullable=True,
|
|
91
|
+
),
|
|
92
|
+
sa.Column("fides_key", sa.String(), nullable=False),
|
|
93
|
+
sa.Column("organization_fides_key", sa.Text(), nullable=True),
|
|
94
|
+
sa.Column("tags", postgresql.ARRAY(sa.String()), nullable=True),
|
|
95
|
+
sa.Column("name", sa.Text(), nullable=True),
|
|
96
|
+
sa.Column("description", sa.Text(), nullable=True),
|
|
97
|
+
sa.Column("taxonomy_type", sa.String(), nullable=False),
|
|
98
|
+
sa.Column("parent_key", sa.Text(), nullable=True),
|
|
99
|
+
sa.Column("active", sa.BOOLEAN(), nullable=False),
|
|
100
|
+
sa.ForeignKeyConstraint(
|
|
101
|
+
["parent_key"], ["taxonomy_element.fides_key"], ondelete="RESTRICT"
|
|
102
|
+
),
|
|
103
|
+
sa.ForeignKeyConstraint(
|
|
104
|
+
["taxonomy_type"], ["taxonomy.fides_key"], ondelete="CASCADE"
|
|
105
|
+
),
|
|
106
|
+
sa.PrimaryKeyConstraint("fides_key"),
|
|
107
|
+
sa.UniqueConstraint("id", name="uq_taxonomy_element_id"),
|
|
108
|
+
)
|
|
109
|
+
op.create_index(
|
|
110
|
+
op.f("ix_taxonomy_element_fides_key"),
|
|
111
|
+
"taxonomy_element",
|
|
112
|
+
["fides_key"],
|
|
113
|
+
unique=True,
|
|
114
|
+
)
|
|
115
|
+
op.create_index(
|
|
116
|
+
op.f("ix_taxonomy_element_active"), "taxonomy_element", ["active"], unique=False
|
|
117
|
+
)
|
|
118
|
+
op.create_index(
|
|
119
|
+
op.f("ix_taxonomy_element_parent_key"),
|
|
120
|
+
"taxonomy_element",
|
|
121
|
+
["parent_key"],
|
|
122
|
+
unique=False,
|
|
123
|
+
)
|
|
124
|
+
op.create_index(
|
|
125
|
+
op.f("ix_taxonomy_element_taxonomy_type"),
|
|
126
|
+
"taxonomy_element",
|
|
127
|
+
["taxonomy_type"],
|
|
128
|
+
unique=False,
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
# Create taxonomy_usage table
|
|
132
|
+
op.create_table(
|
|
133
|
+
"taxonomy_usage",
|
|
134
|
+
sa.Column("id", sa.String(length=255), nullable=False),
|
|
135
|
+
sa.Column(
|
|
136
|
+
"created_at",
|
|
137
|
+
sa.DateTime(timezone=True),
|
|
138
|
+
server_default=sa.text("now()"),
|
|
139
|
+
nullable=True,
|
|
140
|
+
),
|
|
141
|
+
sa.Column(
|
|
142
|
+
"updated_at",
|
|
143
|
+
sa.DateTime(timezone=True),
|
|
144
|
+
server_default=sa.text("now()"),
|
|
145
|
+
nullable=True,
|
|
146
|
+
),
|
|
147
|
+
sa.Column("source_element_key", sa.String(), nullable=False),
|
|
148
|
+
sa.Column("target_element_key", sa.String(), nullable=False),
|
|
149
|
+
sa.Column("source_taxonomy", sa.String(), nullable=False),
|
|
150
|
+
sa.Column("target_taxonomy", sa.String(), nullable=False),
|
|
151
|
+
sa.ForeignKeyConstraint(
|
|
152
|
+
["source_taxonomy", "target_taxonomy"],
|
|
153
|
+
[
|
|
154
|
+
"taxonomy_allowed_usage.source_taxonomy_key",
|
|
155
|
+
"taxonomy_allowed_usage.target_type",
|
|
156
|
+
],
|
|
157
|
+
name="fk_taxonomy_usage_allowed",
|
|
158
|
+
ondelete="RESTRICT",
|
|
159
|
+
),
|
|
160
|
+
sa.PrimaryKeyConstraint("id"),
|
|
161
|
+
sa.UniqueConstraint(
|
|
162
|
+
"source_element_key",
|
|
163
|
+
"target_element_key",
|
|
164
|
+
name="uq_taxonomy_usage",
|
|
165
|
+
),
|
|
166
|
+
)
|
|
167
|
+
op.create_index(
|
|
168
|
+
op.f("ix_taxonomy_usage_source_element_key"),
|
|
169
|
+
"taxonomy_usage",
|
|
170
|
+
["source_element_key"],
|
|
171
|
+
unique=False,
|
|
172
|
+
)
|
|
173
|
+
op.create_index(
|
|
174
|
+
op.f("ix_taxonomy_usage_id"), "taxonomy_usage", ["id"], unique=False
|
|
175
|
+
)
|
|
176
|
+
op.create_index(
|
|
177
|
+
op.f("ix_taxonomy_usage_source_taxonomy"),
|
|
178
|
+
"taxonomy_usage",
|
|
179
|
+
["source_taxonomy"],
|
|
180
|
+
unique=False,
|
|
181
|
+
)
|
|
182
|
+
op.create_index(
|
|
183
|
+
op.f("ix_taxonomy_usage_target_element_key"),
|
|
184
|
+
"taxonomy_usage",
|
|
185
|
+
["target_element_key"],
|
|
186
|
+
unique=False,
|
|
187
|
+
)
|
|
188
|
+
op.create_index(
|
|
189
|
+
op.f("ix_taxonomy_usage_target_taxonomy"),
|
|
190
|
+
"taxonomy_usage",
|
|
191
|
+
["target_taxonomy"],
|
|
192
|
+
unique=False,
|
|
193
|
+
)
|
|
194
|
+
|
|
195
|
+
# Seed legacy taxonomies that are managed by the system
|
|
196
|
+
op.execute(
|
|
197
|
+
"""
|
|
198
|
+
INSERT INTO taxonomy (id, created_at, updated_at, fides_key, organization_fides_key, tags, name, description)
|
|
199
|
+
VALUES
|
|
200
|
+
('data_category', now(), now(), 'data_category', NULL, NULL, 'Data categories', 'Taxonomy for data categories'),
|
|
201
|
+
('data_use', now(), now(), 'data_use', NULL, NULL, 'Data uses', 'Taxonomy for data uses'),
|
|
202
|
+
('data_subject', now(), now(), 'data_subject', NULL, NULL, 'Data subjects', 'Taxonomy for data subjects'),
|
|
203
|
+
('system_group', now(), now(), 'system_group', NULL, NULL, 'System groups', 'Taxonomy for system groups')
|
|
204
|
+
"""
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
def downgrade():
|
|
209
|
+
# Drop taxonomy_usage
|
|
210
|
+
op.drop_index(
|
|
211
|
+
op.f("ix_taxonomy_usage_source_element_key"), table_name="taxonomy_usage"
|
|
212
|
+
)
|
|
213
|
+
op.drop_index(
|
|
214
|
+
op.f("ix_taxonomy_usage_target_taxonomy"), table_name="taxonomy_usage"
|
|
215
|
+
)
|
|
216
|
+
op.drop_index(
|
|
217
|
+
op.f("ix_taxonomy_usage_target_element_key"), table_name="taxonomy_usage"
|
|
218
|
+
)
|
|
219
|
+
op.drop_index(
|
|
220
|
+
op.f("ix_taxonomy_usage_source_taxonomy"), table_name="taxonomy_usage"
|
|
221
|
+
)
|
|
222
|
+
op.drop_index(op.f("ix_taxonomy_usage_id"), table_name="taxonomy_usage")
|
|
223
|
+
op.drop_table("taxonomy_usage")
|
|
224
|
+
|
|
225
|
+
# Drop taxonomy_element
|
|
226
|
+
op.drop_index(
|
|
227
|
+
op.f("ix_taxonomy_element_taxonomy_type"), table_name="taxonomy_element"
|
|
228
|
+
)
|
|
229
|
+
op.drop_index(op.f("ix_taxonomy_element_parent_key"), table_name="taxonomy_element")
|
|
230
|
+
op.drop_index(op.f("ix_taxonomy_element_active"), table_name="taxonomy_element")
|
|
231
|
+
op.drop_index(op.f("ix_taxonomy_element_fides_key"), table_name="taxonomy_element")
|
|
232
|
+
op.drop_table("taxonomy_element")
|
|
233
|
+
|
|
234
|
+
# Drop taxonomy_allowed_usage
|
|
235
|
+
op.drop_table("taxonomy_allowed_usage")
|
|
236
|
+
|
|
237
|
+
# Drop taxonomy
|
|
238
|
+
op.drop_index(op.f("ix_taxonomy_fides_key"), table_name="taxonomy")
|
|
239
|
+
op.drop_table("taxonomy")
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from functools import partial
|
|
2
|
-
from typing import Dict, List, Optional,
|
|
2
|
+
from typing import Dict, List, Optional, Union
|
|
3
3
|
|
|
4
4
|
from fastapi import Depends, HTTPException, Query, Response, Security
|
|
5
5
|
from fastapi.concurrency import run_in_threadpool
|
|
@@ -11,17 +11,16 @@ from fideslang.models import Dataset as FideslangDataset
|
|
|
11
11
|
from pydantic import ValidationError as PydanticValidationError
|
|
12
12
|
from sqlalchemy import not_, select
|
|
13
13
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
14
|
-
from sqlalchemy.orm import
|
|
14
|
+
from sqlalchemy.orm import load_only
|
|
15
15
|
from starlette import status
|
|
16
16
|
from starlette.status import (
|
|
17
17
|
HTTP_200_OK,
|
|
18
|
+
HTTP_400_BAD_REQUEST,
|
|
18
19
|
HTTP_404_NOT_FOUND,
|
|
19
20
|
HTTP_422_UNPROCESSABLE_ENTITY,
|
|
20
21
|
)
|
|
21
22
|
|
|
22
|
-
from fides.api.api.deps import get_db
|
|
23
23
|
from fides.api.common_exceptions import KeyOrNameAlreadyExists, ValidationError
|
|
24
|
-
from fides.api.db.base_class import get_key_from_data
|
|
25
24
|
from fides.api.db.crud import list_resource_query
|
|
26
25
|
from fides.api.db.ctl_session import get_async_db
|
|
27
26
|
from fides.api.models.connectionconfig import ConnectionConfig, ConnectionType
|
|
@@ -37,9 +36,8 @@ from fides.api.schemas.taxonomy_extensions import (
|
|
|
37
36
|
DataUse,
|
|
38
37
|
DataUseCreateOrUpdate,
|
|
39
38
|
)
|
|
40
|
-
from fides.api.service.deps import get_dataset_service
|
|
39
|
+
from fides.api.service.deps import get_dataset_service, get_taxonomy_service
|
|
41
40
|
from fides.api.util.api_router import APIRouter
|
|
42
|
-
from fides.api.util.errors import FidesError, ForbiddenIsDefaultTaxonomyError
|
|
43
41
|
from fides.api.util.filter_utils import apply_filters_to_query
|
|
44
42
|
from fides.common.api.scope_registry import (
|
|
45
43
|
CTL_DATASET_CREATE,
|
|
@@ -57,18 +55,12 @@ from fides.service.dataset.dataset_service import (
|
|
|
57
55
|
DatasetNotFoundException,
|
|
58
56
|
DatasetService,
|
|
59
57
|
)
|
|
58
|
+
from fides.service.taxonomy.taxonomy_service import TaxonomyService
|
|
60
59
|
|
|
61
60
|
from fides.api.models.sql_models import ( # type: ignore[attr-defined] # isort: skip
|
|
62
61
|
Dataset as CtlDataset,
|
|
63
62
|
)
|
|
64
63
|
|
|
65
|
-
from fides.api.models.sql_models import ( # type: ignore[attr-defined] # isort: skip
|
|
66
|
-
DataCategory as DataCategoryDbModel,
|
|
67
|
-
DataSubject as DataSubjectDbModel,
|
|
68
|
-
DataUse as DataUseDbModel,
|
|
69
|
-
ModelWithDefaultField,
|
|
70
|
-
)
|
|
71
|
-
|
|
72
64
|
# We create routers to override specific methods in those defined in generic.py
|
|
73
65
|
# when we need more custom implementations for only some of the methods in a router.
|
|
74
66
|
|
|
@@ -354,135 +346,6 @@ def clean_datasets(
|
|
|
354
346
|
)
|
|
355
347
|
|
|
356
348
|
|
|
357
|
-
def activate_taxonomy_parents(
|
|
358
|
-
resource: Union[DataCategoryDbModel, DataUseDbModel, DataSubjectDbModel],
|
|
359
|
-
db: Session,
|
|
360
|
-
) -> None:
|
|
361
|
-
"""
|
|
362
|
-
Activates parents to match newly-active taxonomy node.
|
|
363
|
-
"""
|
|
364
|
-
parent = resource.parent
|
|
365
|
-
if parent:
|
|
366
|
-
parent.active = True
|
|
367
|
-
db.commit()
|
|
368
|
-
|
|
369
|
-
activate_taxonomy_parents(parent, db)
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
def deactivate_taxonomy_node_and_descendants(
|
|
373
|
-
resource: Union[DataCategoryDbModel, DataUseDbModel, DataSubjectDbModel],
|
|
374
|
-
db: Session,
|
|
375
|
-
) -> None:
|
|
376
|
-
"""
|
|
377
|
-
Recursively de-activates all descendants of a given taxonomy node.
|
|
378
|
-
"""
|
|
379
|
-
resource.active = False
|
|
380
|
-
db.commit()
|
|
381
|
-
children = resource.children
|
|
382
|
-
|
|
383
|
-
for child in children:
|
|
384
|
-
# Deactivate current child
|
|
385
|
-
child.active = False
|
|
386
|
-
db.commit()
|
|
387
|
-
|
|
388
|
-
# Recursively deactivate all descendants of this child
|
|
389
|
-
deactivate_taxonomy_node_and_descendants(child, db)
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
def validate_and_create_taxonomy(
|
|
393
|
-
db: Session,
|
|
394
|
-
model: Union[
|
|
395
|
-
Type[DataCategoryDbModel], Type[DataUseDbModel], Type[DataSubjectDbModel]
|
|
396
|
-
],
|
|
397
|
-
validation_schema: type,
|
|
398
|
-
data: Union[
|
|
399
|
-
DataCategoryCreateOrUpdate, DataUseCreateOrUpdate, DataSubjectCreateOrUpdate
|
|
400
|
-
],
|
|
401
|
-
) -> Dict:
|
|
402
|
-
"""
|
|
403
|
-
Validate and create a taxonomy element.
|
|
404
|
-
"""
|
|
405
|
-
if not data.fides_key:
|
|
406
|
-
raise FidesError(f"Fides key is required to create a {model.__name__} resource")
|
|
407
|
-
if isinstance(data, ModelWithDefaultField) and data.is_default:
|
|
408
|
-
raise ForbiddenIsDefaultTaxonomyError(
|
|
409
|
-
model.__name__, data.fides_key, action="create"
|
|
410
|
-
)
|
|
411
|
-
validated_taxonomy = validation_schema(**data.model_dump(mode="json"))
|
|
412
|
-
return model.create(db=db, data=validated_taxonomy.model_dump(mode="json"))
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
def validate_and_update_taxonomy(
|
|
416
|
-
db: Session,
|
|
417
|
-
resource: Union[DataCategoryDbModel, DataUseDbModel, DataSubjectDbModel],
|
|
418
|
-
validation_schema: type,
|
|
419
|
-
data: Union[
|
|
420
|
-
DataCategoryCreateOrUpdate, DataUseCreateOrUpdate, DataSubjectCreateOrUpdate
|
|
421
|
-
],
|
|
422
|
-
) -> Dict:
|
|
423
|
-
"""
|
|
424
|
-
Validate and update a taxonomy element.
|
|
425
|
-
"""
|
|
426
|
-
if (
|
|
427
|
-
isinstance(data, ModelWithDefaultField)
|
|
428
|
-
and data.is_default != resource.is_default
|
|
429
|
-
):
|
|
430
|
-
raise ForbiddenIsDefaultTaxonomyError(
|
|
431
|
-
"resource", data.fides_key, action="modify"
|
|
432
|
-
)
|
|
433
|
-
|
|
434
|
-
# If active field is being updated, cascade change either up or down
|
|
435
|
-
if hasattr(data, "active"):
|
|
436
|
-
if data.active:
|
|
437
|
-
activate_taxonomy_parents(resource, db)
|
|
438
|
-
else:
|
|
439
|
-
# Cascade down - deactivate current node and children to match newly-deactivated taxonomy item
|
|
440
|
-
deactivate_taxonomy_node_and_descendants(resource, db)
|
|
441
|
-
|
|
442
|
-
validated_taxonomy = validation_schema(**data.model_dump(mode="json"))
|
|
443
|
-
return resource.update(db=db, data=validated_taxonomy.model_dump(mode="json"))
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
def create_or_update_taxonomy(
|
|
447
|
-
db: Session,
|
|
448
|
-
data: Union[
|
|
449
|
-
DataCategoryCreateOrUpdate, DataUseCreateOrUpdate, DataSubjectCreateOrUpdate
|
|
450
|
-
],
|
|
451
|
-
model: Union[
|
|
452
|
-
Type[DataCategoryDbModel], Type[DataUseDbModel], Type[DataSubjectDbModel]
|
|
453
|
-
],
|
|
454
|
-
validation_schema: type,
|
|
455
|
-
) -> Dict:
|
|
456
|
-
"""
|
|
457
|
-
Create or update a taxonomy element.
|
|
458
|
-
If the element is deactivated, it will be updated and re-activated, along with its parents.
|
|
459
|
-
"""
|
|
460
|
-
if data.fides_key is None:
|
|
461
|
-
disabled_resource_with_name = (
|
|
462
|
-
db.query(model)
|
|
463
|
-
.filter(
|
|
464
|
-
model.active.is_(False),
|
|
465
|
-
model.name == data.name,
|
|
466
|
-
)
|
|
467
|
-
.first()
|
|
468
|
-
)
|
|
469
|
-
data.fides_key = get_key_from_data(
|
|
470
|
-
{"key": data.fides_key, "name": data.name}, validation_schema.__name__
|
|
471
|
-
)
|
|
472
|
-
if data.parent_key if hasattr(data, "parent_key") else None:
|
|
473
|
-
# Updates fides_key if it is not the root level taxonomy node
|
|
474
|
-
data.fides_key = f"{data.parent_key}.{data.fides_key}" # type: ignore[union-attr]
|
|
475
|
-
if disabled_resource_with_name:
|
|
476
|
-
data.active = True
|
|
477
|
-
activate_taxonomy_parents(disabled_resource_with_name, db)
|
|
478
|
-
return validate_and_update_taxonomy(
|
|
479
|
-
db, disabled_resource_with_name, validation_schema, data
|
|
480
|
-
)
|
|
481
|
-
return validate_and_create_taxonomy(db, model, validation_schema, data)
|
|
482
|
-
|
|
483
|
-
return validate_and_create_taxonomy(db, model, validation_schema, data)
|
|
484
|
-
|
|
485
|
-
|
|
486
349
|
@data_use_router.post(
|
|
487
350
|
"/data_use",
|
|
488
351
|
dependencies=[Security(verify_oauth_client, scopes=[DATA_USE_CREATE])],
|
|
@@ -492,19 +355,21 @@ def create_or_update_taxonomy(
|
|
|
492
355
|
)
|
|
493
356
|
async def create_data_use(
|
|
494
357
|
data_use: DataUseCreateOrUpdate,
|
|
495
|
-
|
|
358
|
+
taxonomy_service: TaxonomyService = Depends(get_taxonomy_service),
|
|
496
359
|
) -> Dict:
|
|
497
360
|
"""
|
|
498
361
|
Create a data use. Updates existing data use if data use with name already exists and is disabled.
|
|
499
362
|
"""
|
|
500
363
|
try:
|
|
501
|
-
return
|
|
364
|
+
return taxonomy_service.create_or_update_element(
|
|
365
|
+
"data_uses", data_use.model_dump()
|
|
366
|
+
)
|
|
502
367
|
except KeyOrNameAlreadyExists:
|
|
503
368
|
raise HTTPException(
|
|
504
369
|
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
505
370
|
detail=f"Data use with key {data_use.fides_key} or name {data_use.name} already exists.",
|
|
506
371
|
)
|
|
507
|
-
except PydanticValidationError as e:
|
|
372
|
+
except (ValidationError, PydanticValidationError) as e:
|
|
508
373
|
raise HTTPException(
|
|
509
374
|
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
510
375
|
detail=str(e),
|
|
@@ -520,21 +385,26 @@ async def create_data_use(
|
|
|
520
385
|
)
|
|
521
386
|
async def create_data_category(
|
|
522
387
|
data_category: DataCategoryCreateOrUpdate,
|
|
523
|
-
|
|
388
|
+
taxonomy_service: TaxonomyService = Depends(get_taxonomy_service),
|
|
524
389
|
) -> Dict:
|
|
525
390
|
"""
|
|
526
391
|
Create a data category
|
|
527
392
|
"""
|
|
528
393
|
|
|
529
394
|
try:
|
|
530
|
-
return
|
|
531
|
-
|
|
395
|
+
return taxonomy_service.create_or_update_element(
|
|
396
|
+
"data_categories", data_category.model_dump()
|
|
532
397
|
)
|
|
533
398
|
except KeyOrNameAlreadyExists:
|
|
534
399
|
raise HTTPException(
|
|
535
400
|
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
536
401
|
detail=f"Data category with key {data_category.fides_key} or name {data_category.name} already exists.",
|
|
537
402
|
)
|
|
403
|
+
except (ValidationError, PydanticValidationError) as e:
|
|
404
|
+
raise HTTPException(
|
|
405
|
+
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
406
|
+
detail=str(e),
|
|
407
|
+
)
|
|
538
408
|
|
|
539
409
|
|
|
540
410
|
@data_subject_router.post(
|
|
@@ -546,21 +416,26 @@ async def create_data_category(
|
|
|
546
416
|
)
|
|
547
417
|
async def create_data_subject(
|
|
548
418
|
data_subject: DataSubjectCreateOrUpdate,
|
|
549
|
-
|
|
419
|
+
taxonomy_service: TaxonomyService = Depends(get_taxonomy_service),
|
|
550
420
|
) -> Dict:
|
|
551
421
|
"""
|
|
552
422
|
Create a data subject
|
|
553
423
|
"""
|
|
554
424
|
|
|
555
425
|
try:
|
|
556
|
-
return
|
|
557
|
-
|
|
426
|
+
return taxonomy_service.create_or_update_element(
|
|
427
|
+
"data_subjects", data_subject.model_dump()
|
|
558
428
|
)
|
|
559
429
|
except KeyOrNameAlreadyExists:
|
|
560
430
|
raise HTTPException(
|
|
561
431
|
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
562
432
|
detail=f"Data subject with key {data_subject.fides_key} or name {data_subject.name} already exists.",
|
|
563
433
|
)
|
|
434
|
+
except (ValidationError, PydanticValidationError) as e:
|
|
435
|
+
raise HTTPException(
|
|
436
|
+
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
437
|
+
detail=str(e),
|
|
438
|
+
)
|
|
564
439
|
|
|
565
440
|
|
|
566
441
|
@data_use_router.put(
|
|
@@ -572,19 +447,31 @@ async def create_data_subject(
|
|
|
572
447
|
)
|
|
573
448
|
async def update_data_use(
|
|
574
449
|
data_use: DataUseCreateOrUpdate,
|
|
575
|
-
|
|
450
|
+
taxonomy_service: TaxonomyService = Depends(get_taxonomy_service),
|
|
576
451
|
) -> Dict:
|
|
577
452
|
"""
|
|
578
453
|
Update a data use. Ensures updates to "active" are appropriately cascaded.
|
|
579
454
|
"""
|
|
580
|
-
|
|
581
|
-
resource = DataUseDbModel.get_by(db, field="fides_key", value=data_use.fides_key)
|
|
582
|
-
if not resource:
|
|
455
|
+
if not data_use.fides_key:
|
|
583
456
|
raise HTTPException(
|
|
584
|
-
status_code=
|
|
585
|
-
detail=
|
|
457
|
+
status_code=HTTP_400_BAD_REQUEST,
|
|
458
|
+
detail="fides_key is required for update operations.",
|
|
459
|
+
)
|
|
460
|
+
try:
|
|
461
|
+
result = taxonomy_service.update_element(
|
|
462
|
+
"data_uses", data_use.fides_key, data_use.model_dump()
|
|
463
|
+
)
|
|
464
|
+
if not result:
|
|
465
|
+
raise HTTPException(
|
|
466
|
+
status_code=HTTP_404_NOT_FOUND,
|
|
467
|
+
detail=f"Data use not found with key: {data_use.fides_key}",
|
|
468
|
+
)
|
|
469
|
+
return result
|
|
470
|
+
except (ValidationError, PydanticValidationError) as e:
|
|
471
|
+
raise HTTPException(
|
|
472
|
+
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
473
|
+
detail=str(e),
|
|
586
474
|
)
|
|
587
|
-
return validate_and_update_taxonomy(db, resource, DataUse, data_use)
|
|
588
475
|
|
|
589
476
|
|
|
590
477
|
@data_category_router.put(
|
|
@@ -596,21 +483,31 @@ async def update_data_use(
|
|
|
596
483
|
)
|
|
597
484
|
async def update_data_category(
|
|
598
485
|
data_category: DataCategoryCreateOrUpdate,
|
|
599
|
-
|
|
486
|
+
taxonomy_service: TaxonomyService = Depends(get_taxonomy_service),
|
|
600
487
|
) -> Dict:
|
|
601
488
|
"""
|
|
602
489
|
Update a data category. Ensures updates to "active" are appropriately cascaded.
|
|
603
490
|
"""
|
|
604
|
-
|
|
605
|
-
resource = DataCategoryDbModel.get_by(
|
|
606
|
-
db, field="fides_key", value=data_category.fides_key
|
|
607
|
-
)
|
|
608
|
-
if not resource:
|
|
491
|
+
if not data_category.fides_key:
|
|
609
492
|
raise HTTPException(
|
|
610
|
-
status_code=
|
|
611
|
-
detail=
|
|
493
|
+
status_code=HTTP_400_BAD_REQUEST,
|
|
494
|
+
detail="fides_key is required for update operations.",
|
|
495
|
+
)
|
|
496
|
+
try:
|
|
497
|
+
result = taxonomy_service.update_element(
|
|
498
|
+
"data_categories", data_category.fides_key, data_category.model_dump()
|
|
499
|
+
)
|
|
500
|
+
if not result:
|
|
501
|
+
raise HTTPException(
|
|
502
|
+
status_code=HTTP_404_NOT_FOUND,
|
|
503
|
+
detail=f"Data category not found with key: {data_category.fides_key}",
|
|
504
|
+
)
|
|
505
|
+
return result
|
|
506
|
+
except (ValidationError, PydanticValidationError) as e:
|
|
507
|
+
raise HTTPException(
|
|
508
|
+
status_code=HTTP_422_UNPROCESSABLE_ENTITY,
|
|
509
|
+
detail=str(e),
|
|
612
510
|
)
|
|
613
|
-
return validate_and_update_taxonomy(db, resource, DataCategory, data_category)
|
|
614
511
|
|
|
615
512
|
|
|
616
513
|
GENERIC_OVERRIDES_ROUTER = APIRouter()
|
fides/api/db/base.py
CHANGED
|
@@ -76,6 +76,12 @@ from fides.api.models.storage import StorageConfig
|
|
|
76
76
|
from fides.api.models.system_compass_sync import SystemCompassSync
|
|
77
77
|
from fides.api.models.system_history import SystemHistory
|
|
78
78
|
from fides.api.models.system_manager import SystemManager
|
|
79
|
+
from fides.api.models.taxonomy import (
|
|
80
|
+
Taxonomy,
|
|
81
|
+
TaxonomyAllowedUsage,
|
|
82
|
+
TaxonomyElement,
|
|
83
|
+
TaxonomyUsage,
|
|
84
|
+
)
|
|
79
85
|
from fides.api.models.tcf_publisher_restrictions import (
|
|
80
86
|
TCFConfiguration,
|
|
81
87
|
TCFPublisherRestriction,
|