ethyca-fides 2.67.0rc1__py2.py3-none-any.whl → 2.67.0rc2__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.67.0rc1.dist-info → ethyca_fides-2.67.0rc2.dist-info}/METADATA +1 -1
- {ethyca_fides-2.67.0rc1.dist-info → ethyca_fides-2.67.0rc2.dist-info}/RECORD +101 -101
- fides/_version.py +3 -3
- fides/api/common_exceptions.py +4 -0
- fides/api/graph/execution.py +16 -0
- fides/api/schemas/connection_configuration/connection_secrets_datahub.py +10 -1
- fides/api/service/connectors/base_connector.py +14 -0
- fides/api/service/connectors/bigquery_connector.py +5 -0
- fides/api/service/connectors/query_configs/bigquery_query_config.py +4 -4
- fides/api/service/connectors/query_configs/snowflake_query_config.py +3 -3
- fides/api/service/connectors/snowflake_connector.py +55 -2
- fides/api/service/connectors/sql_connector.py +107 -9
- fides/api/task/graph_task.py +2 -0
- fides/ui-build/static/admin/404.html +1 -1
- fides/ui-build/static/admin/_next/static/chunks/pages/{_app-5c3a63bb1697f34c.js → _app-750d6bd16c971bb9.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/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
- {ethyca_fides-2.67.0rc1.dist-info → ethyca_fides-2.67.0rc2.dist-info}/WHEEL +0 -0
- {ethyca_fides-2.67.0rc1.dist-info → ethyca_fides-2.67.0rc2.dist-info}/entry_points.txt +0 -0
- {ethyca_fides-2.67.0rc1.dist-info → ethyca_fides-2.67.0rc2.dist-info}/licenses/LICENSE +0 -0
- {ethyca_fides-2.67.0rc1.dist-info → ethyca_fides-2.67.0rc2.dist-info}/top_level.txt +0 -0
- /fides/ui-build/static/admin/_next/static/{ZIM71ZcqBBeTYHc-MN9_n → 5x65uIwZtfTiu6ITZ4wqq}/_buildManifest.js +0 -0
- /fides/ui-build/static/admin/_next/static/{ZIM71ZcqBBeTYHc-MN9_n → 5x65uIwZtfTiu6ITZ4wqq}/_ssgManifest.js +0 -0
|
@@ -6,7 +6,7 @@ import paramiko
|
|
|
6
6
|
import sshtunnel # type: ignore
|
|
7
7
|
from aiohttp.client_exceptions import ClientResponseError
|
|
8
8
|
from loguru import logger
|
|
9
|
-
from sqlalchemy import Column, select
|
|
9
|
+
from sqlalchemy import Column, inspect, select
|
|
10
10
|
from sqlalchemy.dialects.postgresql import JSONB
|
|
11
11
|
from sqlalchemy.engine import ( # type: ignore
|
|
12
12
|
Connection,
|
|
@@ -22,6 +22,7 @@ from sqlalchemy.sql.elements import TextClause
|
|
|
22
22
|
from fides.api.common_exceptions import (
|
|
23
23
|
ConnectionException,
|
|
24
24
|
SSHTunnelConfigNotFoundException,
|
|
25
|
+
TableNotFound,
|
|
25
26
|
)
|
|
26
27
|
from fides.api.graph.execution import ExecutionNode
|
|
27
28
|
from fides.api.models.connectionconfig import ConnectionConfig, ConnectionTestStatus
|
|
@@ -189,14 +190,28 @@ class SQLConnector(BaseConnector[Engine]):
|
|
|
189
190
|
|
|
190
191
|
logger.info("Starting data retrieval for {}", node.address)
|
|
191
192
|
with client.connect() as connection:
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
193
|
+
try:
|
|
194
|
+
self.set_schema(connection)
|
|
195
|
+
if (
|
|
196
|
+
query_config.partitioning
|
|
197
|
+
): # only BigQuery supports partitioning, for now
|
|
198
|
+
return self.partitioned_retrieval(query_config, connection, stmt)
|
|
199
|
+
|
|
200
|
+
results = connection.execute(stmt)
|
|
201
|
+
return self.cursor_result_to_rows(results)
|
|
202
|
+
except Exception as exc:
|
|
203
|
+
# Check if table exists using qualified table name
|
|
204
|
+
qualified_table_name = self.get_qualified_table_name(node)
|
|
205
|
+
if not self.table_exists(qualified_table_name):
|
|
206
|
+
# Central decision point - will raise TableNotFound or ConnectionException
|
|
207
|
+
self.handle_table_not_found(
|
|
208
|
+
node=node,
|
|
209
|
+
table_name=qualified_table_name,
|
|
210
|
+
operation_context="data retrieval",
|
|
211
|
+
original_exception=exc,
|
|
212
|
+
)
|
|
213
|
+
# Table exists or can't check - re-raise original exception
|
|
214
|
+
raise
|
|
200
215
|
|
|
201
216
|
def mask_data(
|
|
202
217
|
self,
|
|
@@ -290,3 +305,86 @@ class SQLConnector(BaseConnector[Engine]):
|
|
|
290
305
|
raise NotImplementedError(
|
|
291
306
|
"Partitioned retrieval is only supported for BigQuery currently!"
|
|
292
307
|
)
|
|
308
|
+
|
|
309
|
+
def get_qualified_table_name(self, node: ExecutionNode) -> str:
|
|
310
|
+
"""
|
|
311
|
+
Get the fully qualified table name for this database.
|
|
312
|
+
|
|
313
|
+
Default: Returns the simple collection name
|
|
314
|
+
Override: Database-specific connectors can implement namespace resolution
|
|
315
|
+
"""
|
|
316
|
+
return node.collection.name
|
|
317
|
+
|
|
318
|
+
def table_exists(self, qualified_table_name: str) -> bool:
|
|
319
|
+
"""
|
|
320
|
+
Check if table exists using SQLAlchemy introspection.
|
|
321
|
+
|
|
322
|
+
This is a generic implementation that should work for most SQL databases.
|
|
323
|
+
Override: Connectors can implement database-specific table existence checking
|
|
324
|
+
"""
|
|
325
|
+
try:
|
|
326
|
+
client = self.create_client()
|
|
327
|
+
with client.connect() as connection:
|
|
328
|
+
inspector = inspect(connection)
|
|
329
|
+
|
|
330
|
+
# For simple table names
|
|
331
|
+
if "." not in qualified_table_name:
|
|
332
|
+
return inspector.has_table(qualified_table_name)
|
|
333
|
+
|
|
334
|
+
# For qualified names like schema.table or database.schema.table
|
|
335
|
+
parts = qualified_table_name.split(".")
|
|
336
|
+
|
|
337
|
+
if len(parts) == 2:
|
|
338
|
+
# schema.table format
|
|
339
|
+
schema_name, table_name = parts
|
|
340
|
+
return inspector.has_table(table_name, schema=schema_name)
|
|
341
|
+
|
|
342
|
+
if len(parts) >= 3:
|
|
343
|
+
# database.schema.table format (use schema.table)
|
|
344
|
+
schema_name, table_name = parts[-2], parts[-1]
|
|
345
|
+
return inspector.has_table(table_name, schema=schema_name)
|
|
346
|
+
|
|
347
|
+
# Fallback for unexpected format
|
|
348
|
+
return inspector.has_table(qualified_table_name)
|
|
349
|
+
|
|
350
|
+
except Exception as exc:
|
|
351
|
+
# Graceful fallback - if we can't check, assume table exists
|
|
352
|
+
# to preserve existing behavior for connectors that don't implement this
|
|
353
|
+
logger.error("Unable to check if table exists, assuming it does: {}", exc)
|
|
354
|
+
return True
|
|
355
|
+
|
|
356
|
+
def handle_table_not_found(
|
|
357
|
+
self,
|
|
358
|
+
node: ExecutionNode,
|
|
359
|
+
table_name: str,
|
|
360
|
+
operation_context: str,
|
|
361
|
+
original_exception: Optional[Exception] = None,
|
|
362
|
+
) -> None:
|
|
363
|
+
"""
|
|
364
|
+
Central decision point for table-not-found scenarios.
|
|
365
|
+
|
|
366
|
+
Raises TableNotFound (for collection skipping) or ConnectionException (for hard errors).
|
|
367
|
+
The raised exception will be caught by the @retry decorator in graph_task.py.
|
|
368
|
+
|
|
369
|
+
Args:
|
|
370
|
+
node: The ExecutionNode being processed
|
|
371
|
+
table_name: Name of the missing table
|
|
372
|
+
operation_context: Context like "data retrieval" or "data masking"
|
|
373
|
+
original_exception: The original exception that triggered this check
|
|
374
|
+
"""
|
|
375
|
+
if node.has_outgoing_dependencies():
|
|
376
|
+
# Collection has dependencies - cannot skip safely
|
|
377
|
+
error_msg = (
|
|
378
|
+
f"Table '{table_name}' did not exist during {operation_context}. "
|
|
379
|
+
f"Cannot skip collection '{node.address}' because other collections depend on it."
|
|
380
|
+
)
|
|
381
|
+
if original_exception:
|
|
382
|
+
raise ConnectionException(error_msg) from original_exception
|
|
383
|
+
raise ConnectionException(error_msg)
|
|
384
|
+
|
|
385
|
+
# Safe to skip - raise TableNotFound for @retry decorator to catch
|
|
386
|
+
skip_msg = f"Table '{table_name}' did not exist during {operation_context}."
|
|
387
|
+
if original_exception:
|
|
388
|
+
raise TableNotFound(skip_msg) from original_exception
|
|
389
|
+
|
|
390
|
+
raise TableNotFound(skip_msg)
|
fides/api/task/graph_task.py
CHANGED
|
@@ -18,6 +18,7 @@ from fides.api.common_exceptions import (
|
|
|
18
18
|
NotSupportedForCollection,
|
|
19
19
|
PrivacyRequestErasureEmailSendRequired,
|
|
20
20
|
SkippingConsentPropagation,
|
|
21
|
+
TableNotFound,
|
|
21
22
|
)
|
|
22
23
|
from fides.api.graph.config import (
|
|
23
24
|
ROOT_COLLECTION_ADDRESS,
|
|
@@ -126,6 +127,7 @@ def retry(
|
|
|
126
127
|
CollectionDisabled,
|
|
127
128
|
ActionDisabled,
|
|
128
129
|
NotSupportedForCollection,
|
|
130
|
+
TableNotFound,
|
|
129
131
|
) as exc:
|
|
130
132
|
logger.warning(
|
|
131
133
|
"{} - Skipping collection {} for privacy_request: {}",
|
|
@@ -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/d9924caa849931b3.css" as="style"/><link rel="stylesheet" href="/_next/static/css/d9924caa849931b3.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-90e8ec1fc5c6455b.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-
|
|
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/d9924caa849931b3.css" as="style"/><link rel="stylesheet" href="/_next/static/css/d9924caa849931b3.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-90e8ec1fc5c6455b.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-750d6bd16c971bb9.js" defer=""></script><script src="/_next/static/chunks/pages/404-2d803dab6a00f353.js" defer=""></script><script src="/_next/static/5x65uIwZtfTiu6ITZ4wqq/_buildManifest.js" defer=""></script><script src="/_next/static/5x65uIwZtfTiu6ITZ4wqq/_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":"5x65uIwZtfTiu6ITZ4wqq","nextExport":true,"autoExport":true,"isFallback":false,"scriptLoader":[]}</script></body></html>
|