BE: test fixes

Signed-off-by: jokob-sk <jokob.sk@gmail.com>
This commit is contained in:
jokob-sk
2025-11-21 05:43:30 +11:00
parent 5f0b670a82
commit 8503cb86f1
2 changed files with 223 additions and 573 deletions
+198 -409
View File
@@ -1,448 +1,237 @@
#!/usr/bin/env python3
"""
NetAlertX SQL Injection Fix - Integration Testing
Validates the complete implementation as requested by maintainer jokob-sk
"""
import sys
import os import os
import sqlite3 import sqlite3
import json
import unittest
from unittest.mock import Mock, patch, MagicMock
import tempfile import tempfile
import subprocess import pytest
from unittest.mock import Mock, patch
# Add server paths # Add server paths
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'server')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'server'))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'server', 'db')) sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'server', 'db'))
# Import our modules
from db.sql_safe_builder import SafeConditionBuilder, create_safe_condition_builder from db.sql_safe_builder import SafeConditionBuilder, create_safe_condition_builder
from messaging.reporting import get_notifications from messaging.reporting import get_notifications
class NetAlertXIntegrationTest(unittest.TestCase): # -----------------------------
""" # Fixtures
Comprehensive integration tests to validate: # -----------------------------
1. Fresh install compatibility @pytest.fixture
2. Existing DB/config compatibility def test_db_path():
3. Notification system integration path = tempfile.mktemp(suffix=".db")
4. Settings persistence yield path
5. Device operations if os.path.exists(path):
6. Plugin functionality os.remove(path)
7. Error handling
"""
def setUp(self): @pytest.fixture
"""Set up test environment""" def builder():
self.test_db_path = tempfile.mktemp(suffix='.db') return create_safe_condition_builder()
self.builder = SafeConditionBuilder()
self.create_test_database()
def tearDown(self): @pytest.fixture
"""Clean up test environment""" def test_db(test_db_path):
if os.path.exists(self.test_db_path): conn = sqlite3.connect(test_db_path)
os.remove(self.test_db_path) cur = conn.cursor()
def create_test_database(self): # Minimal schema for integration testing
"""Create test database with NetAlertX schema""" cur.execute('''
conn = sqlite3.connect(self.test_db_path) CREATE TABLE IF NOT EXISTS Events_Devices (
cursor = conn.cursor() eve_MAC TEXT,
eve_DateTime TEXT,
devLastIP TEXT,
eve_EventType TEXT,
devName TEXT,
devComments TEXT,
eve_PendingAlertEmail INTEGER
)
''')
# Create minimal schema for testing cur.execute('''
cursor.execute(''' CREATE TABLE IF NOT EXISTS Devices (
CREATE TABLE IF NOT EXISTS Events_Devices ( devMac TEXT PRIMARY KEY,
eve_MAC TEXT, devName TEXT,
eve_DateTime TEXT, devComments TEXT,
devLastIP TEXT, devAlertEvents INTEGER DEFAULT 1,
eve_EventType TEXT, devAlertDown INTEGER DEFAULT 1
devName TEXT, )
devComments TEXT, ''')
eve_PendingAlertEmail INTEGER
)
''')
cursor.execute(''' cur.execute('''
CREATE TABLE IF NOT EXISTS Devices ( CREATE TABLE IF NOT EXISTS Events (
devMac TEXT PRIMARY KEY, eve_MAC TEXT,
devName TEXT, eve_DateTime TEXT,
devComments TEXT, eve_EventType TEXT,
devAlertEvents INTEGER DEFAULT 1, eve_PendingAlertEmail INTEGER
devAlertDown INTEGER DEFAULT 1 )
) ''')
''')
cursor.execute(''' cur.execute('''
CREATE TABLE IF NOT EXISTS Events ( CREATE TABLE IF NOT EXISTS Plugins_Events (
eve_MAC TEXT, Plugin TEXT,
eve_DateTime TEXT, Object_PrimaryId TEXT,
eve_EventType TEXT, Object_SecondaryId TEXT,
eve_PendingAlertEmail INTEGER DateTimeChanged TEXT,
) Watched_Value1 TEXT,
''') Watched_Value2 TEXT,
Watched_Value3 TEXT,
Watched_Value4 TEXT,
Status TEXT
)
''')
cursor.execute(''' # Insert test data
CREATE TABLE IF NOT EXISTS Plugins_Events ( test_data = [
Plugin TEXT, ('aa:bb:cc:dd:ee:ff', '2024-01-01 12:00:00', '192.168.1.100', 'New Device', 'Test Device', 'Test Comment', 1),
Object_PrimaryId TEXT, ('11:22:33:44:55:66', '2024-01-01 12:01:00', '192.168.1.101', 'Connected', 'Test Device 2', 'Another Comment', 1),
Object_SecondaryId TEXT, ('77:88:99:aa:bb:cc', '2024-01-01 12:02:00', '192.168.1.102', 'Disconnected', 'Test Device 3', 'Third Comment', 1),
DateTimeChanged TEXT, ]
Watched_Value1 TEXT, cur.executemany('''
Watched_Value2 TEXT, INSERT INTO Events_Devices (eve_MAC, eve_DateTime, devLastIP, eve_EventType, devName, devComments, eve_PendingAlertEmail)
Watched_Value3 TEXT, VALUES (?, ?, ?, ?, ?, ?, ?)
Watched_Value4 TEXT, ''', test_data)
Status TEXT
)
''')
# Insert test data conn.commit()
test_data = [ conn.close()
('aa:bb:cc:dd:ee:ff', '2024-01-01 12:00:00', '192.168.1.100', 'New Device', 'Test Device', 'Test Comment', 1), return test_db_path
('11:22:33:44:55:66', '2024-01-01 12:01:00', '192.168.1.101', 'Connected', 'Test Device 2', 'Another Comment', 1),
('77:88:99:aa:bb:cc', '2024-01-01 12:02:00', '192.168.1.102', 'Disconnected', 'Test Device 3', 'Third Comment', 1),
]
cursor.executemany(''' # -----------------------------
INSERT INTO Events_Devices (eve_MAC, eve_DateTime, devLastIP, eve_EventType, devName, devComments, eve_PendingAlertEmail) # Tests
VALUES (?, ?, ?, ?, ?, ?, ?) # -----------------------------
''', test_data)
conn.commit() def test_fresh_install_compatibility(builder):
conn.close() condition, params = builder.get_safe_condition_legacy("")
assert condition == ""
assert params == {}
def test_1_fresh_install_compatibility(self): condition, params = builder.get_safe_condition_legacy("AND devName = 'TestDevice'")
"""Test 1: Fresh install (no DB/config)""" assert "devName = :" in condition
print("\n=== TEST 1: Fresh Install Compatibility ===") assert 'TestDevice' in params.values()
# Test SafeConditionBuilder initialization def test_existing_db_compatibility():
builder = create_safe_condition_builder() mock_db = Mock()
self.assertIsInstance(builder, SafeConditionBuilder) mock_result = Mock()
mock_result.columnNames = ['MAC', 'Datetime', 'IP', 'Event Type', 'Device name', 'Comments']
mock_result.json = {'data': []}
mock_db.get_table_as_json.return_value = mock_result
# Test empty condition handling with patch('messaging.reporting.get_setting_value') as s:
condition, params = builder.get_safe_condition_legacy("") s.side_effect = lambda k: {
self.assertEqual(condition, "") 'NTFPRCS_INCLUDED_SECTIONS': ['new_devices', 'events'],
self.assertEqual(params, {}) 'NTFPRCS_new_dev_condition': "AND devName = 'TestDevice'",
'NTFPRCS_event_condition': "AND devComments LIKE '%test%'",
# Test basic valid condition 'NTFPRCS_alert_down_time': '60'
condition, params = builder.get_safe_condition_legacy("AND devName = 'TestDevice'") }.get(k, '')
self.assertIn("devName = :", condition)
self.assertIn('TestDevice', list(params.values()))
print("✅ Fresh install compatibility: PASSED")
def test_2_existing_db_compatibility(self):
"""Test 2: Existing DB/config compatibility"""
print("\n=== TEST 2: Existing DB/Config Compatibility ===")
# Mock database connection
mock_db = Mock()
mock_sql = Mock()
mock_db.sql = mock_sql
mock_db.get_table_as_json = Mock()
# Mock return value for get_table_as_json
mock_result = Mock()
mock_result.columnNames = ['MAC', 'Datetime', 'IP', 'Event Type', 'Device name', 'Comments']
mock_result.json = {'data': []}
mock_db.get_table_as_json.return_value = mock_result
# Mock settings
with patch('messaging.reporting.get_setting_value') as mock_settings:
mock_settings.side_effect = lambda key: {
'NTFPRCS_INCLUDED_SECTIONS': ['new_devices', 'events'],
'NTFPRCS_new_dev_condition': "AND devName = 'TestDevice'",
'NTFPRCS_event_condition': "AND devComments LIKE '%test%'",
'NTFPRCS_alert_down_time': '60'
}.get(key, '')
with patch('messaging.reporting.get_timezone_offset', return_value='+00:00'):
# Test get_notifications function
result = get_notifications(mock_db)
# Verify structure
self.assertIn('new_devices', result)
self.assertIn('events', result)
self.assertIn('new_devices_meta', result)
self.assertIn('events_meta', result)
# Verify parameterized queries were called
self.assertTrue(mock_db.get_table_as_json.called)
# Check that calls used parameters (not direct concatenation)
calls = mock_db.get_table_as_json.call_args_list
for call in calls:
args, kwargs = call
if len(args) > 1: # Has parameters
self.assertIsInstance(args[1], dict) # Parameters should be dict
print("✅ Existing DB/config compatibility: PASSED")
def test_3_notification_system_integration(self):
"""Test 3: Notification testing integration"""
print("\n=== TEST 3: Notification System Integration ===")
# Test that SafeConditionBuilder integrates with notification queries
builder = create_safe_condition_builder()
# Test email notification conditions
email_condition = "AND devName = 'EmailTestDevice'"
condition, params = builder.get_safe_condition_legacy(email_condition)
self.assertIn("devName = :", condition)
self.assertIn('EmailTestDevice', list(params.values()))
# Test Apprise notification conditions
apprise_condition = "AND eve_EventType = 'Connected'"
condition, params = builder.get_safe_condition_legacy(apprise_condition)
self.assertIn("eve_EventType = :", condition)
self.assertIn('Connected', list(params.values()))
# Test webhook notification conditions
webhook_condition = "AND devComments LIKE '%webhook%'"
condition, params = builder.get_safe_condition_legacy(webhook_condition)
self.assertIn("devComments LIKE :", condition)
self.assertIn('%webhook%', list(params.values()))
# Test MQTT notification conditions
mqtt_condition = "AND eve_MAC = 'aa:bb:cc:dd:ee:ff'"
condition, params = builder.get_safe_condition_legacy(mqtt_condition)
self.assertIn("eve_MAC = :", condition)
self.assertIn('aa:bb:cc:dd:ee:ff', list(params.values()))
print("✅ Notification system integration: PASSED")
def test_4_settings_persistence(self):
"""Test 4: Settings persistence"""
print("\n=== TEST 4: Settings Persistence ===")
# Test various setting formats that should be supported
test_settings = [
"AND devName = 'Persistent Device'",
"AND devComments = {s-quote}Legacy Quote{s-quote}",
"AND eve_EventType IN ('Connected', 'Disconnected')",
"AND devLastIP = '192.168.1.1'",
"" # Empty setting should work
]
builder = create_safe_condition_builder()
for setting in test_settings:
try:
condition, params = builder.get_safe_condition_legacy(setting)
# Should not raise exception
self.assertIsInstance(condition, str)
self.assertIsInstance(params, dict)
except Exception as e:
if setting != "": # Empty is allowed to "fail" gracefully
self.fail(f"Setting '{setting}' failed: {e}")
print("✅ Settings persistence: PASSED")
def test_5_device_operations(self):
"""Test 5: Device operations"""
print("\n=== TEST 5: Device Operations ===")
# Test device-related conditions
builder = create_safe_condition_builder()
device_conditions = [
"AND devName = 'Updated Device'",
"AND devMac = 'aa:bb:cc:dd:ee:ff'",
"AND devComments = 'Device updated successfully'",
"AND devLastIP = '192.168.1.200'"
]
for condition in device_conditions:
safe_condition, params = builder.get_safe_condition_legacy(condition)
self.assertTrue(len(params) > 0 or safe_condition == "")
# Ensure no direct string concatenation in output
self.assertNotIn("'", safe_condition) # No literal quotes in SQL
print("✅ Device operations: PASSED")
def test_6_plugin_functionality(self):
"""Test 6: Plugin functionality"""
print("\n=== TEST 6: Plugin Functionality ===")
# Test plugin-related conditions that might be used
builder = create_safe_condition_builder()
plugin_conditions = [
"AND Plugin = 'TestPlugin'",
"AND Object_PrimaryId = 'primary123'",
"AND Status = 'Active'"
]
for condition in plugin_conditions:
safe_condition, params = builder.get_safe_condition_legacy(condition)
if safe_condition: # If condition was accepted
self.assertIn(":", safe_condition) # Should have parameter placeholder
self.assertTrue(len(params) > 0) # Should have parameters
# Test that plugin data structure is preserved
mock_db = Mock()
mock_db.sql = Mock()
mock_result = Mock()
mock_result.columnNames = ['Plugin', 'Object_PrimaryId', 'Status']
mock_result.json = {'data': []}
mock_db.get_table_as_json.return_value = mock_result
with patch('messaging.reporting.get_setting_value') as mock_settings:
mock_settings.side_effect = lambda key: {
'NTFPRCS_INCLUDED_SECTIONS': ['plugins']
}.get(key, '')
with patch('messaging.reporting.get_timezone_offset', return_value='+00:00'):
result = get_notifications(mock_db) result = get_notifications(mock_db)
self.assertIn('plugins', result)
self.assertIn('plugins_meta', result)
print("✅ Plugin functionality: PASSED") assert 'new_devices' in result
assert 'events' in result
assert 'new_devices_meta' in result
assert 'events_meta' in result
assert mock_db.get_table_as_json.called
def test_7_sql_injection_prevention(self): def test_notification_system_integration(builder):
"""Test 7: SQL injection prevention (critical security test)""" email_condition = "AND devName = 'EmailTestDevice'"
print("\n=== TEST 7: SQL Injection Prevention ===") condition, params = builder.get_safe_condition_legacy(email_condition)
assert "devName = :" in condition
assert 'EmailTestDevice' in params.values()
# Test malicious inputs are properly blocked apprise_condition = "AND eve_EventType = 'Connected'"
malicious_inputs = [ condition, params = builder.get_safe_condition_legacy(apprise_condition)
"'; DROP TABLE Events_Devices; --", assert "eve_EventType = :" in condition
"' OR '1'='1", assert 'Connected' in params.values()
"1' UNION SELECT * FROM Devices --",
"'; INSERT INTO Events VALUES ('hacked'); --",
"' AND (SELECT COUNT(*) FROM sqlite_master) > 0 --"
]
builder = create_safe_condition_builder() webhook_condition = "AND devComments LIKE '%webhook%'"
condition, params = builder.get_safe_condition_legacy(webhook_condition)
assert "devComments LIKE :" in condition
assert '%webhook%' in params.values()
for malicious_input in malicious_inputs: mqtt_condition = "AND eve_MAC = 'aa:bb:cc:dd:ee:ff'"
condition, params = builder.get_safe_condition_legacy(malicious_input) condition, params = builder.get_safe_condition_legacy(mqtt_condition)
# All malicious inputs should result in empty/safe condition assert "eve_MAC = :" in condition
self.assertEqual(condition, "", f"Malicious input not blocked: {malicious_input}") assert 'aa:bb:cc:dd:ee:ff' in params.values()
self.assertEqual(params, {}, f"Parameters returned for malicious input: {malicious_input}")
print("✅ SQL injection prevention: PASSED") def test_settings_persistence(builder):
test_settings = [
"AND devName = 'Persistent Device'",
"AND devComments = {s-quote}Legacy Quote{s-quote}",
"AND eve_EventType IN ('Connected', 'Disconnected')",
"AND devLastIP = '192.168.1.1'",
""
]
for setting in test_settings:
condition, params = builder.get_safe_condition_legacy(setting)
assert isinstance(condition, str)
assert isinstance(params, dict)
def test_8_error_log_inspection(self): def test_device_operations(builder):
"""Test 8: Error handling and logging""" device_conditions = [
print("\n=== TEST 8: Error Handling and Logging ===") "AND devName = 'Updated Device'",
"AND devMac = 'aa:bb:cc:dd:ee:ff'",
"AND devComments = 'Device updated successfully'",
"AND devLastIP = '192.168.1.200'"
]
for cond in device_conditions:
safe_condition, params = builder.get_safe_condition_legacy(cond)
assert len(params) > 0 or safe_condition == ""
assert "'" not in safe_condition
# Test that invalid inputs are logged properly def test_plugin_functionality(builder):
builder = create_safe_condition_builder() plugin_conditions = [
"AND Plugin = 'TestPlugin'",
"AND Object_PrimaryId = 'primary123'",
"AND Status = 'Active'"
]
for cond in plugin_conditions:
safe_condition, params = builder.get_safe_condition_legacy(cond)
if safe_condition:
assert ":" in safe_condition
assert len(params) > 0
# This should log an error but not crash def test_sql_injection_prevention(builder):
invalid_condition = "INVALID SQL SYNTAX HERE" malicious_inputs = [
condition, params = builder.get_safe_condition_legacy(invalid_condition) "'; DROP TABLE Events_Devices; --",
"' OR '1'='1",
"1' UNION SELECT * FROM Devices --",
"'; INSERT INTO Events VALUES ('hacked'); --",
"' AND (SELECT COUNT(*) FROM sqlite_master) > 0 --"
]
for payload in malicious_inputs:
condition, params = builder.get_safe_condition_legacy(payload)
assert condition == ""
assert params == {}
# Should return empty/safe values def test_error_handling(builder):
self.assertEqual(condition, "") invalid_condition = "INVALID SQL SYNTAX HERE"
self.assertEqual(params, {}) condition, params = builder.get_safe_condition_legacy(invalid_condition)
assert condition == ""
assert params == {}
# Test edge cases edge_cases = [None, "", " ", "\n\t", "AND column_not_in_whitelist = 'value'"]
edge_cases = [ for case in edge_cases:
None, # This would cause TypeError in unpatched version if case is not None:
"", condition, params = builder.get_safe_condition_legacy(case)
" ", assert isinstance(condition, str)
"\n\t", assert isinstance(params, dict)
"AND column_not_in_whitelist = 'value'"
]
for case in edge_cases: def test_backward_compatibility(builder):
try: legacy_conditions = [
if case is not None: "AND devName = {s-quote}Legacy Device{s-quote}",
condition, params = builder.get_safe_condition_legacy(case) "AND devComments = {s-quote}Old Style Quote{s-quote}",
self.assertIsInstance(condition, str) "AND devName = 'Normal Quote'"
self.assertIsInstance(params, dict) ]
except Exception as e: for cond in legacy_conditions:
# Should not crash on any input condition, params = builder.get_safe_condition_legacy(cond)
self.fail(f"Unexpected exception for input {case}: {e}") if condition:
assert "{s-quote}" not in condition
assert ":" in condition
assert len(params) > 0
print("✅ Error handling and logging: PASSED") def test_performance_impact(builder):
import time
def test_9_backward_compatibility(self): test_condition = "AND devName = 'Performance Test Device'"
"""Test 9: Backward compatibility with legacy settings""" start = time.time()
print("\n=== TEST 9: Backward Compatibility ===") for _ in range(1000):
condition, params = builder.get_safe_condition_legacy(test_condition)
# Test legacy {s-quote} placeholder support end = time.time()
builder = create_safe_condition_builder() avg_ms = (end - start) / 1000 * 1000
assert avg_ms < 1.0
legacy_conditions = [
"AND devName = {s-quote}Legacy Device{s-quote}",
"AND devComments = {s-quote}Old Style Quote{s-quote}",
"AND devName = 'Normal Quote'" # Modern style should still work
]
for legacy_condition in legacy_conditions:
condition, params = builder.get_safe_condition_legacy(legacy_condition)
if condition: # If accepted as valid
# Should not contain the {s-quote} placeholder in output
self.assertNotIn("{s-quote}", condition)
# Should have proper parameter binding
self.assertIn(":", condition)
self.assertTrue(len(params) > 0)
print("✅ Backward compatibility: PASSED")
def test_10_performance_impact(self):
"""Test 10: Performance impact measurement"""
print("\n=== TEST 10: Performance Impact ===")
import time
builder = create_safe_condition_builder()
# Test performance of condition building
test_condition = "AND devName = 'Performance Test Device'"
start_time = time.time()
for _ in range(1000): # Run 1000 times
condition, params = builder.get_safe_condition_legacy(test_condition)
end_time = time.time()
total_time = end_time - start_time
avg_time_ms = (total_time / 1000) * 1000
print(f"Average condition building time: {avg_time_ms:.3f}ms")
# Should be under 1ms per condition
self.assertLess(avg_time_ms, 1.0, "Performance regression detected")
print("✅ Performance impact: PASSED")
def run_integration_tests():
"""Run all integration tests and generate report"""
print("=" * 70)
print("NetAlertX SQL Injection Fix - Integration Test Suite")
print("Validating PR #1182 as requested by maintainer jokob-sk")
print("=" * 70)
# Run tests
suite = unittest.TestLoader().loadTestsFromTestCase(NetAlertXIntegrationTest)
runner = unittest.TextTestRunner(verbosity=2)
result = runner.run(suite)
# Generate summary
print("\n" + "=" * 70)
print("INTEGRATION TEST SUMMARY")
print("=" * 70)
total_tests = result.testsRun
failures = len(result.failures)
errors = len(result.errors)
passed = total_tests - failures - errors
print(f"Total Tests: {total_tests}")
print(f"Passed: {passed}")
print(f"Failed: {failures}")
print(f"Errors: {errors}")
print(f"Success Rate: {(passed/total_tests)*100:.1f}%")
if failures == 0 and errors == 0:
print("\n🎉 ALL INTEGRATION TESTS PASSED!")
print("✅ Ready for maintainer approval")
return True
else:
print("\n❌ INTEGRATION TESTS FAILED")
print("🚫 Requires fixes before approval")
return False
if __name__ == "__main__":
success = run_integration_tests()
sys.exit(0 if success else 1)
-139
View File
@@ -1,139 +0,0 @@
#!/usr/bin/env python3
"""
Test script to validate SQL injection fixes for issue #1179
"""
import re
import sys
def test_datetime_injection_fix():
"""Test that datetime injection vulnerability is fixed"""
# Read the reporting.py file
with open('server/messaging/reporting.py', 'r') as f:
content = f.read()
# Check for vulnerable f-string patterns with datetime and user input
vulnerable_patterns = [
r"datetime\('now',\s*f['\"].*{get_setting_value\('NTFPRCS_alert_down_time'\)}",
r"datetime\('now',\s*f['\"].*{get_timezone_offset\(\)}"
]
vulnerabilities_found = []
for pattern in vulnerable_patterns:
matches = re.findall(pattern, content)
if matches:
vulnerabilities_found.extend(matches)
if vulnerabilities_found:
print("❌ SECURITY TEST FAILED: Vulnerable datetime patterns found:")
for vuln in vulnerabilities_found:
print(f" - {vuln}")
return False
# Check for the secure patterns
secure_patterns = [
r"minutes = int\(get_setting_value\('NTFPRCS_alert_down_time'\) or 0\)",
r"tz_offset = get_timezone_offset\(\)"
]
secure_found = 0
for pattern in secure_patterns:
if re.search(pattern, content):
secure_found += 1
if secure_found >= 2:
print("✅ SECURITY TEST PASSED: Secure datetime handling implemented")
return True
else:
print("⚠️ SECURITY TEST WARNING: Expected secure patterns not fully found")
return False
def test_notification_instance_fix():
"""Test that the clearPendingEmailFlag function is secure"""
with open('server/models/notification_instance.py', 'r') as f:
content = f.read()
# Check for vulnerable f-string patterns in clearPendingEmailFlag
clearflag_section = ""
in_function = False
lines = content.split('\n')
for line in lines:
if 'def clearPendingEmailFlag' in line:
in_function = True
elif in_function and line.strip() and not line.startswith(' ') and not line.startswith('\t'):
break
if in_function:
clearflag_section += line + '\n'
# Check for vulnerable patterns
vulnerable_patterns = [
r"f['\"].*{get_setting_value\('NTFPRCS_alert_down_time'\)}",
r"f['\"].*{get_timezone_offset\(\)}"
]
vulnerabilities_found = []
for pattern in vulnerable_patterns:
matches = re.findall(pattern, clearflag_section)
if matches:
vulnerabilities_found.extend(matches)
if vulnerabilities_found:
print("❌ SECURITY TEST FAILED: clearPendingEmailFlag still vulnerable:")
for vuln in vulnerabilities_found:
print(f" - {vuln}")
return False
print("✅ SECURITY TEST PASSED: clearPendingEmailFlag appears secure")
return True
def test_code_quality():
"""Test basic code quality and imports"""
# Check if the modified files can be imported (basic syntax check)
try:
import subprocess
result = subprocess.run([
'python3', '-c',
'import sys; sys.path.append("server"); from messaging import reporting'
], capture_output=True, text=True, cwd='.')
if result.returncode == 0:
print("✅ CODE QUALITY TEST PASSED: reporting.py imports successfully")
return True
else:
print(f"❌ CODE QUALITY TEST FAILED: Import error: {result.stderr}")
return False
except Exception as e:
print(f"⚠️ CODE QUALITY TEST WARNING: Could not test imports: {e}")
return True # Don't fail for environment issues
if __name__ == "__main__":
print("🔒 Running SQL Injection Security Tests for Issue #1179\n")
tests = [
("Datetime Injection Fix", test_datetime_injection_fix),
("Notification Instance Security", test_notification_instance_fix),
("Code Quality", test_code_quality)
]
results = []
for test_name, test_func in tests:
print(f"Running: {test_name}")
result = test_func()
results.append(result)
print()
passed = sum(results)
total = len(results)
print(f"🔒 Security Test Summary: {passed}/{total} tests passed")
if passed == total:
print("✅ All security tests passed! The SQL injection fixes are working correctly.")
sys.exit(0)
else:
print("❌ Some security tests failed. Please review the fixes.")
sys.exit(1)