sql-data-guard 0.1.4__tar.gz → 0.1.6__tar.gz

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.
Files changed (27) hide show
  1. {sql_data_guard-0.1.4/src/sql_data_guard.egg-info → sql_data_guard-0.1.6}/PKG-INFO +1 -1
  2. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/pyproject.toml +1 -1
  3. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard/restriction_verification.py +1 -1
  4. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard/sql_data_guard.py +15 -14
  5. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6/src/sql_data_guard.egg-info}/PKG-INFO +1 -1
  6. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_sql_guard_curr_unit.py +5 -3
  7. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_sql_guard_unit.py +27 -1
  8. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_sql_guard_updates_unit.py +4 -0
  9. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/LICENSE.md +0 -0
  10. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/README.md +0 -0
  11. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/setup.cfg +0 -0
  12. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard/__init__.py +0 -0
  13. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard/rest/__init__.py +0 -0
  14. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard/rest/sql_data_guard_rest.py +0 -0
  15. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard/restriction_validation.py +0 -0
  16. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard/verification_context.py +0 -0
  17. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard/verification_utils.py +0 -0
  18. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard.egg-info/SOURCES.txt +0 -0
  19. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard.egg-info/dependency_links.txt +0 -0
  20. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard.egg-info/requires.txt +0 -0
  21. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/src/sql_data_guard.egg-info/top_level.txt +0 -0
  22. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_duckdb_unit.py +0 -0
  23. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_rest_api_unit.py +0 -0
  24. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_sql_guard_joins_unit.py +0 -0
  25. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_sql_guard_llm.py +0 -0
  26. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_sql_guard_validation_unit.py +0 -0
  27. {sql_data_guard-0.1.4 → sql_data_guard-0.1.6}/test/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql-data-guard
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Safety Layer for LLM Database Interactions
5
5
  Author-email: Imperva - Threat Reseach Infra <ww.dis.imperva.threat-research-infra@thalesgroup.com>
6
6
  License: MIT License
@@ -9,7 +9,7 @@ package-dir = {"" = "src"}
9
9
  extra-index-url = ["https://pypi.org/simple"]
10
10
  [project]
11
11
  name = "sql-data-guard"
12
- version = "0.1.4"
12
+ version = "0.1.6"
13
13
  dependencies = [
14
14
  "sqlglot"
15
15
  ]
@@ -130,7 +130,7 @@ def _verify_restriction(
130
130
  # Handle IN condition correctly
131
131
  if isinstance(exp, expr.In):
132
132
  expr_values = [str(val.this) for val in exp.expressions]
133
- return any(v in values for v in expr_values)
133
+ return all(v in values for v in expr_values)
134
134
 
135
135
  # Handle EQ (=) condition
136
136
  if isinstance(exp, expr.EQ) and isinstance(exp.right, expr.Condition):
@@ -79,7 +79,7 @@ def _verify_where_clause(
79
79
  ):
80
80
  where_clause = select_statement.find(expr.Where)
81
81
  if where_clause:
82
- for sub in where_clause.find_all(expr.Subquery):
82
+ for sub in where_clause.find_all(expr.Subquery, expr.Exists):
83
83
  _verify_query_statement(sub.this, context)
84
84
  _verify_static_expression(select_statement, context)
85
85
  verify_restrictions(select_statement, context, from_tables)
@@ -136,12 +136,10 @@ def _verify_query_statement(query_statement: expr.Query, context: VerificationCo
136
136
  _add_table_alias(cte, context)
137
137
  _verify_query_statement(cte.this, context)
138
138
  from_tables = _verify_from_tables(context, query_statement)
139
- if not context.can_fix:
140
- return query_statement
141
- _verify_select_clause(context, query_statement, from_tables)
142
- _verify_where_clause(context, query_statement, from_tables)
143
- _verify_order_by_clause(context, query_statement)
144
- return query_statement
139
+ if context.can_fix:
140
+ _verify_select_clause(context, query_statement, from_tables)
141
+ _verify_where_clause(context, query_statement, from_tables)
142
+ _verify_sub_queries(context, query_statement)
145
143
 
146
144
 
147
145
  def _verify_from_tables(context, query_statement):
@@ -156,11 +154,12 @@ def _verify_from_tables(context, query_statement):
156
154
  return from_tables
157
155
 
158
156
 
159
- def _verify_order_by_clause(context, query_statement):
160
- for exp_type in [expr.Order, expr.Offset]:
157
+ def _verify_sub_queries(context, query_statement):
158
+ for exp_type in [expr.Order, expr.Offset, expr.Limit, expr.Group, expr.Having]:
161
159
  for exp in find_direct(query_statement, exp_type):
162
- for sub in exp.find_all(expr.Subquery):
163
- _verify_query_statement(sub.this, context)
160
+ if exp:
161
+ for sub in exp.find_all(expr.Subquery):
162
+ _verify_query_statement(sub.this, context)
164
163
 
165
164
 
166
165
  def _verify_select_clause(
@@ -289,6 +288,8 @@ def _get_from_clause_tables(
289
288
  def _add_table_alias(exp: expr.Expression, context: VerificationContext):
290
289
  for table_alias in find_direct(exp, expr.TableAlias):
291
290
  if isinstance(table_alias, expr.TableAlias):
292
- context.dynamic_tables[table_alias.alias_or_name] = {
293
- col.alias_or_name for col in table_alias.columns
294
- }
291
+ if len(table_alias.columns) > 0:
292
+ column_names = {col.alias_or_name for col in table_alias.columns}
293
+ else:
294
+ column_names = {c for c in exp.this.named_selects}
295
+ context.dynamic_tables[table_alias.alias_or_name] = column_names
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sql-data-guard
3
- Version: 0.1.4
3
+ Version: 0.1.6
4
4
  Summary: Safety Layer for LLM Database Interactions
5
5
  Author-email: Imperva - Threat Reseach Infra <ww.dis.imperva.threat-research-infra@thalesgroup.com>
6
6
  License: MIT License
@@ -701,10 +701,12 @@ class TestSQLOrderRestrictions:
701
701
  verify_sql_test(
702
702
  sql,
703
703
  config,
704
- errors=set(), # No errors expected as the restriction matches the IN clause
705
- fix=None, # No fix should be needed
704
+ errors={
705
+ "Missing restriction for table: orders column: account_id value: [124]"
706
+ },
707
+ fix="SELECT product_name FROM orders WHERE (account_id IN (123, 124, 125)) AND account_id = 124",
706
708
  cnn=cnn,
707
- data=[("Product A",), ("Product B",), ("Product C",)],
709
+ data=[("Product B",)],
708
710
  )
709
711
 
710
712
  def test_id_greater_than_122_should_return_error(self, config):
@@ -6,8 +6,8 @@ from typing import Generator
6
6
 
7
7
  import pytest
8
8
 
9
+ from conftest import verify_sql_test
9
10
  from sql_data_guard import verify_sql
10
- from conftest import verify_sql_test, verify_sql_test_data
11
11
 
12
12
 
13
13
  def _get_resource(file_name: str) -> str:
@@ -354,6 +354,32 @@ class TestTrino:
354
354
  )
355
355
 
356
356
 
357
+ class TestTrinoWithRestrictions:
358
+ @pytest.fixture(scope="class")
359
+ def config(self) -> dict:
360
+ return {
361
+ "tables": [
362
+ {
363
+ "table_name": "accounts",
364
+ "columns": ["id", "day", "product_name"],
365
+ "restrictions": [
366
+ {"column": "id", "value": 123},
367
+ ],
368
+ }
369
+ ]
370
+ }
371
+
372
+ @pytest.mark.skip(reason="Bug in sqlglot. Waiting for fix")
373
+ def test_date_add(self, config):
374
+ verify_sql_test(
375
+ "SELECT id FROM accounts WHERE DATE(day) >= DATE_ADD('day', -7, CURRENT_DATE)",
376
+ config,
377
+ dialect="trino",
378
+ errors={"Missing restriction for table: accounts column: id value: 123"},
379
+ fix="SELECT id FROM accounts WHERE DATE(day) >= DATE_ADD('day', -7, CURRENT_DATE) AND id = 123",
380
+ )
381
+
382
+
357
383
  class TestRestrictionsWithDifferentDataTypes:
358
384
  @pytest.fixture(scope="class")
359
385
  def config(self) -> dict:
@@ -705,6 +705,10 @@ class TestMultipleRestriction:
705
705
  verify_sql_test(
706
706
  """SELECT id FROM products1 WHERE id IN (324, 233)""",
707
707
  config,
708
+ errors={
709
+ "Missing restriction for table: products1 column: id value: [324, 224]"
710
+ },
711
+ fix="SELECT id FROM products1 WHERE (id IN (324, 233)) AND id IN (324, 224)",
708
712
  cnn=cnn,
709
713
  data=[["324"]],
710
714
  )
File without changes
File without changes