Spaces:
Sleeping
Sleeping
| """ | |
| Tests for enhanced admin rules with regex and severity support | |
| """ | |
| import sys | |
| from pathlib import Path | |
| # Add backend directory to Python path | |
| backend_dir = Path(__file__).parent.parent | |
| sys.path.insert(0, str(backend_dir)) | |
| import pytest | |
| import tempfile | |
| import os | |
| import re | |
| from api.storage.rules_store import RulesStore | |
| def temp_rules_db(): | |
| """Create a temporary database for testing.""" | |
| with tempfile.NamedTemporaryFile(delete=False, suffix='.db') as f: | |
| db_path = f.name | |
| yield db_path | |
| # Cleanup | |
| if os.path.exists(db_path): | |
| os.unlink(db_path) | |
| def rules_store(temp_rules_db): | |
| """Create a RulesStore instance with temporary database.""" | |
| # RulesStore uses a fixed path, so we'll just use the default | |
| # For tests, it will create/use data/admin_rules.db | |
| # Each test should use unique tenant_id to avoid conflicts | |
| store = RulesStore() | |
| yield store | |
| # Cleanup: Delete test data after each test | |
| # Note: In a real scenario, you'd want to clean up specific tenant data | |
| # For now, tests use unique tenant IDs to avoid conflicts | |
| def test_add_rule_with_regex_and_severity(rules_store): | |
| """Test adding a rule with regex pattern and severity.""" | |
| tenant_id = "test_tenant_regex_severity" # Unique tenant ID | |
| success = rules_store.add_rule( | |
| tenant_id=tenant_id, | |
| rule="Block password queries", | |
| pattern=r".*password.*|.*pwd.*", | |
| severity="high", | |
| description="Blocks any queries containing password or pwd", | |
| enabled=True | |
| ) | |
| assert success is True | |
| # Get detailed rules | |
| rules = rules_store.get_rules_detailed(tenant_id) | |
| assert len(rules) == 1 | |
| assert rules[0]["pattern"] == r".*password.*|.*pwd.*" | |
| assert rules[0]["severity"] == "high" | |
| assert rules[0]["description"] == "Blocks any queries containing password or pwd" | |
| assert rules[0]["enabled"] == 1 | |
| def test_add_rule_without_pattern_uses_rule_text(rules_store): | |
| """Test that if pattern is not provided, rule text is used as pattern.""" | |
| tenant_id = "test_tenant_no_pattern" # Unique tenant ID | |
| rules_store.add_rule( | |
| tenant_id=tenant_id, | |
| rule="Block sensitive data", | |
| severity="medium" | |
| ) | |
| rules = rules_store.get_rules_detailed(tenant_id) | |
| assert len(rules) == 1 | |
| assert rules[0]["pattern"] == "Block sensitive data" | |
| assert rules[0]["severity"] == "medium" | |
| def test_get_rules_backward_compatibility(rules_store): | |
| """Test that get_rules() still returns simple list for backward compatibility.""" | |
| tenant_id = "test_tenant_backward_compat" # Unique tenant ID | |
| rules_store.add_rule( | |
| tenant_id=tenant_id, | |
| rule="Rule 1", | |
| severity="low" | |
| ) | |
| rules_store.add_rule( | |
| tenant_id=tenant_id, | |
| rule="Rule 2", | |
| severity="high" | |
| ) | |
| rules = rules_store.get_rules(tenant_id) | |
| assert isinstance(rules, list) | |
| assert len(rules) == 2 | |
| assert "Rule 1" in rules | |
| assert "Rule 2" in rules | |
| def test_regex_pattern_matching(rules_store): | |
| """Test that regex patterns work correctly.""" | |
| tenant_id = "test_tenant_regex_match" # Unique tenant ID | |
| rules_store.add_rule( | |
| tenant_id=tenant_id, | |
| rule="Email pattern", | |
| pattern=r".*@.*\..*", | |
| severity="medium" | |
| ) | |
| rules = rules_store.get_rules_detailed(tenant_id) | |
| assert len(rules) == 1 | |
| pattern = rules[0]["pattern"] | |
| # Test regex matching | |
| test_cases = [ | |
| ("user@example.com", True), | |
| ("contact me at test@domain.org", True), | |
| ("no email here", False), | |
| ("just text", False) | |
| ] | |
| regex = re.compile(pattern, re.IGNORECASE) | |
| for text, should_match in test_cases: | |
| assert (regex.search(text) is not None) == should_match, f"Failed for: {text}" | |
| def test_severity_levels(rules_store): | |
| """Test different severity levels.""" | |
| tenant_id = "test_tenant_severity" # Unique tenant ID | |
| severities = ["low", "medium", "high", "critical"] | |
| for i, severity in enumerate(severities): | |
| rules_store.add_rule( | |
| tenant_id=tenant_id, | |
| rule=f"Rule {severity}", | |
| severity=severity | |
| ) | |
| rules = rules_store.get_rules_detailed(tenant_id) | |
| assert len(rules) == len(severities) | |
| for rule in rules: | |
| assert rule["severity"] in severities | |
| def test_disabled_rules_not_returned(rules_store): | |
| """Test that disabled rules are not returned by get_rules().""" | |
| tenant_id = "test_tenant_disabled" # Unique tenant ID | |
| rules_store.add_rule( | |
| tenant_id=tenant_id, | |
| rule="Enabled rule", | |
| enabled=True | |
| ) | |
| rules_store.add_rule( | |
| tenant_id=tenant_id, | |
| rule="Disabled rule", | |
| enabled=False | |
| ) | |
| rules = rules_store.get_rules(tenant_id) | |
| assert len(rules) == 1 | |
| assert "Enabled rule" in rules | |
| assert "Disabled rule" not in rules | |
| # But disabled rules should still exist in detailed view (if we add a method for that) | |
| # For now, we rely on enabled column filtering | |
| def test_multiple_tenants_isolation(rules_store): | |
| """Test that rules are properly isolated by tenant.""" | |
| rules_store.add_rule( | |
| tenant_id="tenant1", | |
| rule="Tenant 1 rule", | |
| severity="low" | |
| ) | |
| rules_store.add_rule( | |
| tenant_id="tenant2", | |
| rule="Tenant 2 rule", | |
| severity="high" | |
| ) | |
| tenant1_rules = rules_store.get_rules("tenant1") | |
| tenant2_rules = rules_store.get_rules("tenant2") | |
| assert len(tenant1_rules) == 1 | |
| assert "Tenant 1 rule" in tenant1_rules | |
| assert "Tenant 2 rule" not in tenant1_rules | |
| assert len(tenant2_rules) == 1 | |
| assert "Tenant 2 rule" in tenant2_rules | |
| assert "Tenant 1 rule" not in tenant2_rules | |