AURASHIELDV3 / tests /test_sql_preservation.py
ANJU DEVI
AuraShield V3 Docker deployment
6960b79
Raw
History Blame Contribute Delete
7.12 kB
"""
Test SQL Preservation in Remediation
Verifies that SQL injection fixes preserve:
- Table names
- Column selections
- Authorization clauses (AND NOT role = 'admin')
- Suffix conditions (ORDER BY, LIMIT)
"""
import pytest
import sys
import os
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from gen_ai.model import SecureCodeGenerator
from gen_ai.output_validator import CodeOutputValidator
from governance.safety import SafetyChecker
class TestSQLStructureExtraction:
"""Test the SQL structure extraction logic."""
def setup_method(self):
self.generator = SecureCodeGenerator()
def test_extract_table_name(self):
"""Verify table name is extracted correctly."""
code = "SELECT * FROM orders WHERE id = " + "user_id"
info = self.generator._extract_full_sql_structure(code)
assert info['table'] == 'orders'
def test_extract_select_columns(self):
"""Verify SELECT columns are extracted."""
code = "SELECT id, email, name FROM users WHERE username = " + "input"
info = self.generator._extract_full_sql_structure(code)
assert 'id' in info['select_columns']
assert 'email' in info['select_columns']
def test_extract_where_column(self):
"""Verify WHERE column is extracted."""
code = "SELECT * FROM users WHERE user_id = " + "var"
info = self.generator._extract_full_sql_structure(code)
assert info['column'] == 'user_id'
def test_extract_authorization_suffix(self):
"""Verify authorization clauses are captured."""
code = "SELECT * FROM users WHERE name = 'test' AND NOT role = 'admin'"
info = self.generator._extract_full_sql_structure(code)
assert "AND NOT role = 'admin'" in info['authorization_suffix']
def test_extract_order_by(self):
"""Verify ORDER BY is extracted."""
code = "SELECT * FROM products WHERE category = 'x' ORDER BY price DESC"
info = self.generator._extract_full_sql_structure(code)
assert 'ORDER BY' in info['order_by']
assert 'price' in info['order_by']
def test_extract_limit(self):
"""Verify LIMIT is extracted."""
code = "SELECT * FROM items WHERE active = 1 LIMIT 10"
info = self.generator._extract_full_sql_structure(code)
assert 'LIMIT 10' in info['limit']
class TestSQLPreservationValidation:
"""Test the SQL preservation validator."""
def test_table_mismatch_rejected(self):
"""Reject if table name changes."""
original = "SELECT * FROM orders WHERE id = " + "var"
fixed = "SELECT * FROM users WHERE id = ?"
is_valid, msg = CodeOutputValidator.validate_sql_preservation(original, fixed)
assert not is_valid
assert 'orders' in msg.lower() or 'table' in msg.lower()
def test_authorization_clause_preserved(self):
"""Accept if authorization clause is preserved."""
original = "SELECT * FROM users WHERE name = 'x' AND NOT role = 'admin'"
fixed = "SELECT * FROM users WHERE name = ? AND NOT role = 'admin'"
is_valid, msg = CodeOutputValidator.validate_sql_preservation(original, fixed)
assert is_valid
def test_authorization_clause_lost_rejected(self):
"""Reject if authorization clause is lost."""
original = "SELECT * FROM users WHERE name = 'x' AND NOT role = 'admin'"
fixed = "SELECT * FROM users WHERE name = ?"
is_valid, msg = CodeOutputValidator.validate_sql_preservation(original, fixed)
assert not is_valid
assert 'authorization' in msg.lower() or 'AND NOT' in msg
def test_order_by_preserved(self):
"""Accept if ORDER BY is preserved."""
original = "SELECT * FROM products WHERE cat = 'x' ORDER BY price"
fixed = "SELECT * FROM products WHERE cat = ? ORDER BY price"
is_valid, msg = CodeOutputValidator.validate_sql_preservation(original, fixed)
assert is_valid
def test_order_by_lost_rejected(self):
"""Reject if ORDER BY is lost."""
original = "SELECT * FROM products WHERE cat = 'x' ORDER BY price"
fixed = "SELECT * FROM products WHERE cat = ?"
is_valid, msg = CodeOutputValidator.validate_sql_preservation(original, fixed)
assert not is_valid
assert 'ORDER BY' in msg
def test_limit_preserved(self):
"""Accept if LIMIT is preserved."""
original = "SELECT * FROM items WHERE x = 'y' LIMIT 10"
fixed = "SELECT * FROM items WHERE x = ? LIMIT 10"
is_valid, msg = CodeOutputValidator.validate_sql_preservation(original, fixed)
assert is_valid
class TestGovernanceEnforcement:
"""Test governance rejects non-compliant fixes."""
def setup_method(self):
self.checker = SafetyChecker()
def test_governance_rejects_table_change(self):
"""Governance should reject if table name changes."""
original = "SELECT * FROM orders WHERE id = " + "var"
fixed = "SELECT * FROM users WHERE id = ?"
is_approved, msg = self.checker.check_structure_preservation(original, fixed, "CWE-89")
assert not is_approved
assert 'GOVERNANCE' in msg.upper() or 'table' in msg.lower()
def test_governance_approves_valid_fix(self):
"""Governance should approve correct parameterization."""
original = "SELECT * FROM users WHERE name = 'x'"
fixed = "SELECT * FROM users WHERE name = ?"
is_approved, msg = self.checker.check_structure_preservation(original, fixed, "CWE-89")
assert is_approved
class TestRemediationPreservation:
"""Test end-to-end remediation preserves structure."""
def setup_method(self):
self.generator = SecureCodeGenerator()
def test_python_fix_preserves_table(self):
"""Python fix should preserve table name."""
code = "cursor.execute('SELECT * FROM orders WHERE user_id = ' + uid)"
result = self.generator.generate_fix_with_fallback(code, "CWE-89", "python")
assert 'orders' in result['code']
def test_python_fix_preserves_columns(self):
"""Python fix should preserve column selections."""
code = "cursor.execute('SELECT id, email FROM users WHERE name = ' + name)"
result = self.generator.generate_fix_with_fallback(code, "CWE-89", "python")
# Should have parameterization
assert '?' in result['code']
# Should preserve table
assert 'users' in result['code']
def test_java_fix_preserves_table(self):
"""Java fix should preserve table name."""
code = 'stmt.executeQuery("SELECT * FROM products WHERE id = " + productId)'
result = self.generator.generate_fix_with_fallback(code, "CWE-89", "java")
assert 'products' in result['code']
assert 'PreparedStatement' in result['code']
if __name__ == "__main__":
pytest.main([__file__, "-v"])