ethyca-fides 2.66.1b0__py2.py3-none-any.whl → 2.66.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.

Potentially problematic release.


This version of ethyca-fides might be problematic. Click here for more details.

Files changed (122) hide show
  1. {ethyca_fides-2.66.1b0.dist-info → ethyca_fides-2.66.1b1.dist-info}/METADATA +1 -1
  2. {ethyca_fides-2.66.1b0.dist-info → ethyca_fides-2.66.1b1.dist-info}/RECORD +122 -122
  3. fides/_version.py +3 -3
  4. fides/api/api/v1/endpoints/dataset_config_endpoints.py +13 -5
  5. fides/api/api/v1/endpoints/user_endpoints.py +83 -7
  6. fides/api/graph/execution.py +30 -0
  7. fides/api/oauth/roles.py +2 -0
  8. fides/api/schemas/application_config.py +11 -1
  9. fides/api/service/connectors/base_connector.py +1 -0
  10. fides/api/service/connectors/bigquery_connector.py +67 -19
  11. fides/api/service/connectors/dynamodb_connector.py +2 -1
  12. fides/api/service/connectors/fides_connector.py +1 -0
  13. fides/api/service/connectors/http_connector.py +1 -0
  14. fides/api/service/connectors/manual_task_connector.py +1 -0
  15. fides/api/service/connectors/manual_webhook_connector.py +2 -1
  16. fides/api/service/connectors/mongodb_connector.py +1 -0
  17. fides/api/service/connectors/okta_connector.py +1 -0
  18. fides/api/service/connectors/query_configs/bigquery_query_config.py +45 -20
  19. fides/api/service/connectors/rds_mysql_connector.py +1 -0
  20. fides/api/service/connectors/rds_postgres_connector.py +1 -0
  21. fides/api/service/connectors/s3_connector.py +1 -0
  22. fides/api/service/connectors/saas_connector.py +1 -0
  23. fides/api/service/connectors/scylla_connector.py +1 -0
  24. fides/api/service/connectors/sql_connector.py +36 -4
  25. fides/api/service/connectors/website_connector.py +1 -0
  26. fides/api/task/deprecated_graph_task.py +24 -6
  27. fides/api/task/execute_request_tasks.py +88 -11
  28. fides/api/task/graph_task.py +11 -0
  29. fides/api/task/manual/manual_task_graph_task.py +1 -0
  30. fides/common/api/scope_registry.py +3 -0
  31. fides/config/utils.py +1 -0
  32. fides/ui-build/static/admin/404.html +1 -1
  33. fides/ui-build/static/admin/_next/static/chunks/pages/{_app-f66151e613766714.js → _app-a152f52351c84ef4.js} +1 -1
  34. fides/ui-build/static/admin/add-systems/manual.html +1 -1
  35. fides/ui-build/static/admin/add-systems/multiple.html +1 -1
  36. fides/ui-build/static/admin/add-systems.html +1 -1
  37. fides/ui-build/static/admin/consent/configure/add-vendors.html +1 -1
  38. fides/ui-build/static/admin/consent/configure.html +1 -1
  39. fides/ui-build/static/admin/consent/privacy-experience/[id].html +1 -1
  40. fides/ui-build/static/admin/consent/privacy-experience/new.html +1 -1
  41. fides/ui-build/static/admin/consent/privacy-experience.html +1 -1
  42. fides/ui-build/static/admin/consent/privacy-notices/[id].html +1 -1
  43. fides/ui-build/static/admin/consent/privacy-notices/new.html +1 -1
  44. fides/ui-build/static/admin/consent/privacy-notices.html +1 -1
  45. fides/ui-build/static/admin/consent/properties.html +1 -1
  46. fides/ui-build/static/admin/consent/reporting.html +1 -1
  47. fides/ui-build/static/admin/consent.html +1 -1
  48. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn]/[resourceUrn].html +1 -1
  49. fides/ui-build/static/admin/data-catalog/[systemId]/projects/[projectUrn].html +1 -1
  50. fides/ui-build/static/admin/data-catalog/[systemId]/projects.html +1 -1
  51. fides/ui-build/static/admin/data-catalog/[systemId]/resources/[resourceUrn].html +1 -1
  52. fides/ui-build/static/admin/data-catalog/[systemId]/resources.html +1 -1
  53. fides/ui-build/static/admin/data-catalog.html +1 -1
  54. fides/ui-build/static/admin/data-discovery/action-center/[monitorId]/[systemId].html +1 -1
  55. fides/ui-build/static/admin/data-discovery/action-center/[monitorId].html +1 -1
  56. fides/ui-build/static/admin/data-discovery/action-center.html +1 -1
  57. fides/ui-build/static/admin/data-discovery/activity.html +1 -1
  58. fides/ui-build/static/admin/data-discovery/detection/[resourceUrn].html +1 -1
  59. fides/ui-build/static/admin/data-discovery/detection.html +1 -1
  60. fides/ui-build/static/admin/data-discovery/discovery/[resourceUrn].html +1 -1
  61. fides/ui-build/static/admin/data-discovery/discovery.html +1 -1
  62. fides/ui-build/static/admin/datamap.html +1 -1
  63. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName]/[...subfieldNames].html +1 -1
  64. fides/ui-build/static/admin/dataset/[datasetId]/[collectionName].html +1 -1
  65. fides/ui-build/static/admin/dataset/[datasetId].html +1 -1
  66. fides/ui-build/static/admin/dataset/new.html +1 -1
  67. fides/ui-build/static/admin/dataset.html +1 -1
  68. fides/ui-build/static/admin/datastore-connection/[id].html +1 -1
  69. fides/ui-build/static/admin/datastore-connection/new.html +1 -1
  70. fides/ui-build/static/admin/datastore-connection.html +1 -1
  71. fides/ui-build/static/admin/index.html +1 -1
  72. fides/ui-build/static/admin/integrations/[id].html +1 -1
  73. fides/ui-build/static/admin/integrations.html +1 -1
  74. fides/ui-build/static/admin/lib/fides-preview.js +1 -1
  75. fides/ui-build/static/admin/lib/fides-tcf.js +3 -3
  76. fides/ui-build/static/admin/lib/fides.js +1 -1
  77. fides/ui-build/static/admin/login/[provider].html +1 -1
  78. fides/ui-build/static/admin/login.html +1 -1
  79. fides/ui-build/static/admin/messaging/[id].html +1 -1
  80. fides/ui-build/static/admin/messaging/add-template.html +1 -1
  81. fides/ui-build/static/admin/messaging.html +1 -1
  82. fides/ui-build/static/admin/poc/ant-components.html +1 -1
  83. fides/ui-build/static/admin/poc/form-experiments/AntForm.html +1 -1
  84. fides/ui-build/static/admin/poc/form-experiments/FormikAntFormItem.html +1 -1
  85. fides/ui-build/static/admin/poc/form-experiments/FormikControlled.html +1 -1
  86. fides/ui-build/static/admin/poc/form-experiments/FormikField.html +1 -1
  87. fides/ui-build/static/admin/poc/form-experiments/FormikSpreadField.html +1 -1
  88. fides/ui-build/static/admin/poc/forms.html +1 -1
  89. fides/ui-build/static/admin/poc/table-migration.html +1 -1
  90. fides/ui-build/static/admin/privacy-requests/[id].html +1 -1
  91. fides/ui-build/static/admin/privacy-requests/configure/messaging.html +1 -1
  92. fides/ui-build/static/admin/privacy-requests/configure/storage.html +1 -1
  93. fides/ui-build/static/admin/privacy-requests/configure.html +1 -1
  94. fides/ui-build/static/admin/privacy-requests.html +1 -1
  95. fides/ui-build/static/admin/properties/[id].html +1 -1
  96. fides/ui-build/static/admin/properties/add-property.html +1 -1
  97. fides/ui-build/static/admin/properties.html +1 -1
  98. fides/ui-build/static/admin/reporting/datamap.html +1 -1
  99. fides/ui-build/static/admin/settings/about/alpha.html +1 -1
  100. fides/ui-build/static/admin/settings/about.html +1 -1
  101. fides/ui-build/static/admin/settings/consent/[configuration_id]/[purpose_id].html +1 -1
  102. fides/ui-build/static/admin/settings/consent.html +1 -1
  103. fides/ui-build/static/admin/settings/custom-fields.html +1 -1
  104. fides/ui-build/static/admin/settings/domain-records.html +1 -1
  105. fides/ui-build/static/admin/settings/domains.html +1 -1
  106. fides/ui-build/static/admin/settings/email-templates.html +1 -1
  107. fides/ui-build/static/admin/settings/locations.html +1 -1
  108. fides/ui-build/static/admin/settings/organization.html +1 -1
  109. fides/ui-build/static/admin/settings/regulations.html +1 -1
  110. fides/ui-build/static/admin/systems/configure/[id]/test-datasets.html +1 -1
  111. fides/ui-build/static/admin/systems/configure/[id].html +1 -1
  112. fides/ui-build/static/admin/systems.html +1 -1
  113. fides/ui-build/static/admin/taxonomy.html +1 -1
  114. fides/ui-build/static/admin/user-management/new.html +1 -1
  115. fides/ui-build/static/admin/user-management/profile/[id].html +1 -1
  116. fides/ui-build/static/admin/user-management.html +1 -1
  117. {ethyca_fides-2.66.1b0.dist-info → ethyca_fides-2.66.1b1.dist-info}/WHEEL +0 -0
  118. {ethyca_fides-2.66.1b0.dist-info → ethyca_fides-2.66.1b1.dist-info}/entry_points.txt +0 -0
  119. {ethyca_fides-2.66.1b0.dist-info → ethyca_fides-2.66.1b1.dist-info}/licenses/LICENSE +0 -0
  120. {ethyca_fides-2.66.1b0.dist-info → ethyca_fides-2.66.1b1.dist-info}/top_level.txt +0 -0
  121. /fides/ui-build/static/admin/_next/static/{jeMhTiDcCKPk_H4S0nSQq → cUz9aQNEfv77_K6F0m_Ja}/_buildManifest.js +0 -0
  122. /fides/ui-build/static/admin/_next/static/{jeMhTiDcCKPk_H4S0nSQq → cUz9aQNEfv77_K6F0m_Ja}/_ssgManifest.js +0 -0
@@ -27,11 +27,13 @@ from fides.api.graph.execution import ExecutionNode
27
27
  from fides.api.models.connectionconfig import ConnectionConfig, ConnectionTestStatus
28
28
  from fides.api.models.policy import Policy
29
29
  from fides.api.models.privacy_request import PrivacyRequest, RequestTask
30
+ from fides.api.schemas.application_config import SqlDryRunMode
30
31
  from fides.api.schemas.connection_configuration import ConnectionConfigSecretsSchema
31
32
  from fides.api.service.connectors.base_connector import BaseConnector
32
33
  from fides.api.service.connectors.query_configs.query_config import SQLQueryConfig
33
34
  from fides.api.util.collection_util import Row
34
35
  from fides.config import get_config
36
+ from fides.config.config_proxy import ConfigProxy
35
37
 
36
38
  from fides.api.models.sql_models import ( # type: ignore[attr-defined] # isort: skip
37
39
  Dataset as CtlDataset,
@@ -58,6 +60,23 @@ class SQLConnector(BaseConnector[Engine]):
58
60
  )
59
61
  self.ssh_server: sshtunnel._ForwardServer = None
60
62
 
63
+ def should_dry_run(self, mode_to_check: SqlDryRunMode) -> bool:
64
+ """
65
+ Check if SQL dry run is enabled for the specified mode.
66
+
67
+ Args:
68
+ mode_to_check: The SqlDryRunMode to check for
69
+
70
+ Returns:
71
+ bool: True if the current mode matches the mode to check
72
+ """
73
+ from fides.api.api.deps import get_autoclose_db_session as get_db
74
+
75
+ with get_db() as db:
76
+ config_proxy = ConfigProxy(db)
77
+ current_mode = getattr(config_proxy.execution, "sql_dry_run", None)
78
+ return current_mode == mode_to_check
79
+
61
80
  @staticmethod
62
81
  def cursor_result_to_rows(results: CursorResult) -> List[Row]:
63
82
  """Convert SQLAlchemy results to a list of dictionaries"""
@@ -140,6 +159,10 @@ class SQLConnector(BaseConnector[Engine]):
140
159
  if query is None:
141
160
  return []
142
161
 
162
+ if self.should_dry_run(SqlDryRunMode.access):
163
+ logger.warning(f"SQL DRY RUN - Would execute SQL: {query}")
164
+ return []
165
+
143
166
  with client.connect() as connection:
144
167
  self.set_schema(connection)
145
168
  results = connection.execute(query)
@@ -160,6 +183,10 @@ class SQLConnector(BaseConnector[Engine]):
160
183
  if stmt is None:
161
184
  return []
162
185
 
186
+ if self.should_dry_run(SqlDryRunMode.access):
187
+ logger.warning(f"SQL DRY RUN - Would execute SQL: {stmt}")
188
+ return []
189
+
163
190
  logger.info("Starting data retrieval for {}", node.address)
164
191
  with client.connect() as connection:
165
192
  self.set_schema(connection)
@@ -178,20 +205,25 @@ class SQLConnector(BaseConnector[Engine]):
178
205
  privacy_request: PrivacyRequest,
179
206
  request_task: RequestTask,
180
207
  rows: List[Row],
208
+ input_data: Optional[Dict[str, List[Any]]] = None,
181
209
  ) -> int:
182
210
  """Execute a masking request. Returns the number of records masked"""
183
211
  query_config = self.query_config(node)
184
212
  update_ct = 0
185
213
  client = self.client()
214
+
186
215
  for row in rows:
187
216
  update_stmt: Optional[TextClause] = query_config.generate_update_stmt(
188
217
  row, policy, privacy_request
189
218
  )
190
219
  if update_stmt is not None:
191
- with client.connect() as connection:
192
- self.set_schema(connection)
193
- results: LegacyCursorResult = connection.execute(update_stmt)
194
- update_ct = update_ct + results.rowcount
220
+ if self.should_dry_run(SqlDryRunMode.erasure):
221
+ logger.warning(f"SQL DRY RUN - Would execute SQL: {update_stmt}")
222
+ else:
223
+ with client.connect() as connection:
224
+ self.set_schema(connection)
225
+ results: LegacyCursorResult = connection.execute(update_stmt)
226
+ update_ct = update_ct + results.rowcount
195
227
  return update_ct
196
228
 
197
229
  def close(self) -> None:
@@ -75,6 +75,7 @@ class WebsiteConnector(BaseConnector):
75
75
  privacy_request: PrivacyRequest,
76
76
  request_task: RequestTask,
77
77
  rows: List[Row],
78
+ input_data: Optional[Dict[str, List[Any]]] = None,
78
79
  ) -> int:
79
80
  """DSR execution not supported for website connector"""
80
81
  return 0
@@ -1,4 +1,5 @@
1
1
  # pylint: disable=too-many-lines
2
+ from functools import partial
2
3
  from typing import Any, Callable, Dict, List, Optional, Set, Tuple, Union
3
4
 
4
5
  import dask
@@ -252,16 +253,33 @@ def run_erasure_request_deprecated( # pylint: disable = too-many-arguments
252
253
 
253
254
  access_request_data[ROOT_COLLECTION_ADDRESS.value] = [identity]
254
255
 
255
- dsk: Dict[CollectionAddress, Any] = {
256
- k: (
257
- t.erasure_request,
256
+ # Build the dask task graph for erasure, ensuring we also pass along the
257
+ # upstream access data that may be required by the connector (e.g. BigQuery
258
+ # delete statements). We accomplish this by partially applying the
259
+ # `inputs` kwarg on each task's `erasure_request` method. The resulting
260
+ # callable accepts the original positional arguments expected by Dask.
261
+
262
+ dsk: Dict[CollectionAddress, Any] = {}
263
+ for k, t in env.items():
264
+ # Collect upstream access data in the same order as the input keys
265
+ upstream_access_data: List[List[Row]] = [
266
+ access_request_data.get(str(input_key), [])
267
+ for input_key in t.execution_node.input_keys
268
+ ]
269
+
270
+ # Bind the `inputs` keyword argument so it is supplied when the task executes
271
+ erasure_fn_with_inputs = partial(
272
+ t.erasure_request, inputs=upstream_access_data
273
+ )
274
+
275
+ # Build the task tuple: (callable, retrieved_data, *prereqs)
276
+ dsk[k] = (
277
+ erasure_fn_with_inputs,
258
278
  access_request_data.get(
259
279
  str(k), []
260
- ), # Pass in the results of the access request for this collection
280
+ ), # Data retrieved for this collection
261
281
  *_evaluate_erasure_dependencies(t, erasure_end_nodes),
262
282
  )
263
- for k, t in env.items()
264
- }
265
283
 
266
284
  # root node returns 0 to be consistent with the output of the other erasure tasks
267
285
  dsk[ROOT_COLLECTION_ADDRESS] = 0
@@ -298,17 +298,11 @@ def run_access_node(
298
298
  )
299
299
  # Currently, upstream tasks and "input keys" (which are built by data dependencies)
300
300
  # are the same, but they may not be the same in the future.
301
- ordered_upstream_tasks: List[Optional[RequestTask]] = (
302
- _order_tasks_by_input_key(
301
+ upstream_access_data: List[List[Row]] = (
302
+ _build_upstream_access_data(
303
303
  graph_task.execution_node.input_keys, upstream_results
304
304
  )
305
305
  )
306
- # Pass in access data dependencies in the same order as the input keys.
307
- # If we don't have access data for an upstream node, pass in an empty list
308
- upstream_access_data: List[List[Row]] = [
309
- upstream.get_access_data() if upstream else []
310
- for upstream in ordered_upstream_tasks
311
- ]
312
306
  # Run the main access function
313
307
  graph_task.access_request(*upstream_access_data)
314
308
 
@@ -359,7 +353,7 @@ def run_erasure_node(
359
353
  session,
360
354
  ) as resources:
361
355
  # Build GraphTask resource to facilitate execution
362
- graph_task: GraphTask = create_graph_task(
356
+ erasure_graph_task: GraphTask = create_graph_task(
363
357
  session, request_task, resources
364
358
  )
365
359
  # Get access data that was saved in the erasure format that was collected from the
@@ -368,8 +362,24 @@ def run_erasure_node(
368
362
  request_task.get_data_for_erasures() or []
369
363
  )
370
364
 
371
- # Run the main erasure function!
372
- graph_task.erasure_request(retrieved_data)
365
+ upstream_access_data: List[List[Row]] = []
366
+
367
+ try:
368
+ upstream_access_data = (
369
+ get_upstream_access_data_for_erasure_task(
370
+ request_task, session, resources
371
+ )
372
+ )
373
+ except Exception as e:
374
+ logger.error(
375
+ f"Unable to get upstream access data for erasure task {request_task.collection_address}: {e}"
376
+ )
377
+
378
+ # Run the main erasure function, passing along the upstream access data.
379
+ # The extra data is currently only needed for generating BigQuery delete statements.
380
+ erasure_graph_task.erasure_request(
381
+ retrieved_data, inputs=upstream_access_data
382
+ )
373
383
 
374
384
  queue_downstream_tasks_with_retries(
375
385
  self,
@@ -487,6 +497,73 @@ def _order_tasks_by_input_key(
487
497
  return tasks
488
498
 
489
499
 
500
+ def get_upstream_access_data_for_erasure_task(
501
+ erasure_request_task: RequestTask,
502
+ session: Session,
503
+ resources: TaskResources,
504
+ ) -> List[List[Row]]:
505
+ """
506
+ Retrieves upstream access data for a given erasure request task.
507
+
508
+ This function finds the corresponding access task for the erasure task,
509
+ creates a GraphTask to extract input keys, and builds the upstream access data
510
+ needed for erasure operations (particularly for BigQuery delete statements).
511
+
512
+ Args:
513
+ erasure_request_task: The erasure task that needs upstream access data
514
+ session: Database session for querying
515
+ resources: Task resources for creating GraphTask
516
+
517
+ Returns:
518
+ List[List[Row]]: Upstream access data ordered by input keys
519
+
520
+ Raises:
521
+ Exception: If the corresponding access task cannot be found
522
+ """
523
+ # Get the corresponding access task for the current erasure task
524
+ access_request_task = (
525
+ session.query(RequestTask)
526
+ .filter(
527
+ RequestTask.privacy_request_id == erasure_request_task.privacy_request_id,
528
+ RequestTask.collection_address == erasure_request_task.collection_address,
529
+ RequestTask.action_type == ActionType.access,
530
+ )
531
+ .first()
532
+ )
533
+
534
+ if not access_request_task:
535
+ raise Exception(
536
+ f"Unable to find access request task for erasure task {erasure_request_task.collection_address}"
537
+ )
538
+
539
+ # Convert the request task to a GraphTask to get the input_keys
540
+ access_graph_task: GraphTask = create_graph_task(
541
+ session, access_request_task, resources
542
+ )
543
+
544
+ # Build and return the upstream access data
545
+ return _build_upstream_access_data(
546
+ access_graph_task.execution_node.input_keys,
547
+ access_request_task.upstream_tasks_objects(session),
548
+ )
549
+
550
+
551
+ def _build_upstream_access_data(
552
+ input_keys: List[CollectionAddress],
553
+ upstream_tasks: Query,
554
+ ) -> List[List[Row]]:
555
+ """
556
+ Helper function to build the access data for the current node.
557
+ The access data is passed in the same order as the input keys.
558
+ If we don't have access data for an upstream node, return an empty list.
559
+ """
560
+
561
+ ordered_upstream: List[Optional[RequestTask]] = _order_tasks_by_input_key(
562
+ input_keys, upstream_tasks
563
+ )
564
+ return [task.get_access_data() if task else [] for task in ordered_upstream]
565
+
566
+
490
567
  mapping = {
491
568
  ActionType.access.value: run_access_node,
492
569
  ActionType.erasure.value: run_erasure_node,
@@ -645,9 +645,15 @@ class GraphTask(ABC): # pylint: disable=too-many-instance-attributes
645
645
  self,
646
646
  retrieved_data: List[Row],
647
647
  *erasure_prereqs: int, # TODO Remove when we stop support for DSR 2.0. DSR 3.0 enforces with downstream_tasks.
648
+ inputs: Optional[
649
+ List[List[Row]]
650
+ ] = None, # Upstream data from corresponding access task
648
651
  ) -> int:
649
652
  """Run erasure request"""
650
653
 
654
+ if inputs is None:
655
+ inputs = []
656
+
651
657
  # if there is no primary key specified in the graph node configuration
652
658
  # note this in the execution log and perform no erasures on this node
653
659
  if (
@@ -694,6 +700,10 @@ class GraphTask(ABC): # pylint: disable=too-many-instance-attributes
694
700
  )
695
701
  return 0
696
702
 
703
+ formatted_input_data: NodeInput = self.pre_process_input_data(
704
+ *inputs, group_dependent_fields=True
705
+ )
706
+
697
707
  # Use execution context to capture postprocessor messages
698
708
  with collect_execution_log_messages() as messages:
699
709
  output = self.connector.mask_data(
@@ -702,6 +712,7 @@ class GraphTask(ABC): # pylint: disable=too-many-instance-attributes
702
712
  self.resources.request,
703
713
  self.resources.privacy_request_task,
704
714
  retrieved_data,
715
+ formatted_input_data,
705
716
  )
706
717
 
707
718
  if self.request_task.id:
@@ -268,6 +268,7 @@ class ManualTaskGraphTask(GraphTask):
268
268
  self,
269
269
  retrieved_data: List[Row],
270
270
  *erasure_prereqs: int, # noqa: D401, pylint: disable=unused-argument
271
+ inputs: Optional[List[List[Row]]] = None,
271
272
  ) -> int:
272
273
  """Execute manual-task-driven erasure logic.
273
274
 
@@ -51,6 +51,7 @@ PRIVACY_REQUEST_ACCESS_RESULTS = "privacy-request-access-results"
51
51
  PRIVACY_REQUEST_EMAIL_INTEGRATIONS = "privacy-request-email-integrations"
52
52
  PRIVACY_REQUEST_NOTIFICATIONS = "privacy-request-notifications"
53
53
  READ = "read"
54
+ READ_OWN = "read-own"
54
55
  REGISTER = "register"
55
56
  RESET = "reset"
56
57
  RESPOND = "respond"
@@ -226,6 +227,7 @@ TAXONOMY_DELETE = f"{TAXONOMY}:{DELETE}"
226
227
  USER_CREATE = f"{USER}:{CREATE}"
227
228
  USER_DELETE = f"{USER}:{DELETE}"
228
229
  USER_READ = f"{USER}:{READ}"
230
+ USER_READ_OWN = f"{USER}:{READ_OWN}"
229
231
  USER_UPDATE = f"{USER}:{UPDATE}"
230
232
  USER_PASSWORD_RESET = f"{USER}:{PASSWORD_RESET}"
231
233
 
@@ -354,6 +356,7 @@ SCOPE_DOCS = {
354
356
  USER_UPDATE: "Update users",
355
357
  USER_DELETE: "Remove users",
356
358
  USER_READ: "View users",
359
+ USER_READ_OWN: "View own user",
357
360
  USER_PASSWORD_RESET: "Reset another user's password",
358
361
  USER_PERMISSION_CREATE: "Create user permissions",
359
362
  USER_PERMISSION_UPDATE: "Update user permissions",
fides/config/utils.py CHANGED
@@ -61,6 +61,7 @@ CONFIG_KEY_ALLOWLIST = {
61
61
  "task_retry_backoff",
62
62
  "require_manual_request_approval",
63
63
  "subject_identity_verification_required",
64
+ "sql_dry_run",
64
65
  ],
65
66
  "storage": [
66
67
  "active_default_storage_type",
@@ -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/b81194f2c3930152.css" as="style"/><link rel="stylesheet" href="/_next/static/css/b81194f2c3930152.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-ff4c22c9f0840531.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-f66151e613766714.js" defer=""></script><script src="/_next/static/chunks/pages/404-2d803dab6a00f353.js" defer=""></script><script src="/_next/static/jeMhTiDcCKPk_H4S0nSQq/_buildManifest.js" defer=""></script><script src="/_next/static/jeMhTiDcCKPk_H4S0nSQq/_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":"jeMhTiDcCKPk_H4S0nSQq","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
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/b81194f2c3930152.css" as="style"/><link rel="stylesheet" href="/_next/static/css/b81194f2c3930152.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-ff4c22c9f0840531.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-a152f52351c84ef4.js" defer=""></script><script src="/_next/static/chunks/pages/404-2d803dab6a00f353.js" defer=""></script><script src="/_next/static/cUz9aQNEfv77_K6F0m_Ja/_buildManifest.js" defer=""></script><script src="/_next/static/cUz9aQNEfv77_K6F0m_Ja/_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":"cUz9aQNEfv77_K6F0m_Ja","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>