mirror of
https://github.com/jokob-sk/NetAlertX.git
synced 2025-12-07 09:36:05 -08:00
448
test/integration/integration_test.py
Executable file
448
test/integration/integration_test.py
Executable file
@@ -0,0 +1,448 @@
|
||||
#!/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 sqlite3
|
||||
import json
|
||||
import unittest
|
||||
from unittest.mock import Mock, patch, MagicMock
|
||||
import tempfile
|
||||
import subprocess
|
||||
|
||||
# Add server paths
|
||||
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'))
|
||||
|
||||
# Import our modules
|
||||
from db.sql_safe_builder import SafeConditionBuilder, create_safe_condition_builder
|
||||
from messaging.reporting import get_notifications
|
||||
|
||||
class NetAlertXIntegrationTest(unittest.TestCase):
|
||||
"""
|
||||
Comprehensive integration tests to validate:
|
||||
1. Fresh install compatibility
|
||||
2. Existing DB/config compatibility
|
||||
3. Notification system integration
|
||||
4. Settings persistence
|
||||
5. Device operations
|
||||
6. Plugin functionality
|
||||
7. Error handling
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
"""Set up test environment"""
|
||||
self.test_db_path = tempfile.mktemp(suffix='.db')
|
||||
self.builder = SafeConditionBuilder()
|
||||
self.create_test_database()
|
||||
|
||||
def tearDown(self):
|
||||
"""Clean up test environment"""
|
||||
if os.path.exists(self.test_db_path):
|
||||
os.remove(self.test_db_path)
|
||||
|
||||
def create_test_database(self):
|
||||
"""Create test database with NetAlertX schema"""
|
||||
conn = sqlite3.connect(self.test_db_path)
|
||||
cursor = conn.cursor()
|
||||
|
||||
# Create minimal schema for testing
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS Events_Devices (
|
||||
eve_MAC TEXT,
|
||||
eve_DateTime TEXT,
|
||||
devLastIP TEXT,
|
||||
eve_EventType TEXT,
|
||||
devName TEXT,
|
||||
devComments TEXT,
|
||||
eve_PendingAlertEmail INTEGER
|
||||
)
|
||||
''')
|
||||
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS Devices (
|
||||
devMac TEXT PRIMARY KEY,
|
||||
devName TEXT,
|
||||
devComments TEXT,
|
||||
devAlertEvents INTEGER DEFAULT 1,
|
||||
devAlertDown INTEGER DEFAULT 1
|
||||
)
|
||||
''')
|
||||
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS Events (
|
||||
eve_MAC TEXT,
|
||||
eve_DateTime TEXT,
|
||||
eve_EventType TEXT,
|
||||
eve_PendingAlertEmail INTEGER
|
||||
)
|
||||
''')
|
||||
|
||||
cursor.execute('''
|
||||
CREATE TABLE IF NOT EXISTS Plugins_Events (
|
||||
Plugin TEXT,
|
||||
Object_PrimaryId TEXT,
|
||||
Object_SecondaryId TEXT,
|
||||
DateTimeChanged TEXT,
|
||||
Watched_Value1 TEXT,
|
||||
Watched_Value2 TEXT,
|
||||
Watched_Value3 TEXT,
|
||||
Watched_Value4 TEXT,
|
||||
Status TEXT
|
||||
)
|
||||
''')
|
||||
|
||||
# Insert test data
|
||||
test_data = [
|
||||
('aa:bb:cc:dd:ee:ff', '2024-01-01 12:00:00', '192.168.1.100', 'New Device', 'Test Device', 'Test Comment', 1),
|
||||
('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)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?)
|
||||
''', test_data)
|
||||
|
||||
conn.commit()
|
||||
conn.close()
|
||||
|
||||
def test_1_fresh_install_compatibility(self):
|
||||
"""Test 1: Fresh install (no DB/config)"""
|
||||
print("\n=== TEST 1: Fresh Install Compatibility ===")
|
||||
|
||||
# Test SafeConditionBuilder initialization
|
||||
builder = create_safe_condition_builder()
|
||||
self.assertIsInstance(builder, SafeConditionBuilder)
|
||||
|
||||
# Test empty condition handling
|
||||
condition, params = builder.get_safe_condition_legacy("")
|
||||
self.assertEqual(condition, "")
|
||||
self.assertEqual(params, {})
|
||||
|
||||
# Test basic valid condition
|
||||
condition, params = builder.get_safe_condition_legacy("AND devName = 'TestDevice'")
|
||||
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, '')
|
||||
|
||||
result = get_notifications(mock_db)
|
||||
self.assertIn('plugins', result)
|
||||
self.assertIn('plugins_meta', result)
|
||||
|
||||
print("✅ Plugin functionality: PASSED")
|
||||
|
||||
def test_7_sql_injection_prevention(self):
|
||||
"""Test 7: SQL injection prevention (critical security test)"""
|
||||
print("\n=== TEST 7: SQL Injection Prevention ===")
|
||||
|
||||
# Test malicious inputs are properly blocked
|
||||
malicious_inputs = [
|
||||
"'; DROP TABLE Events_Devices; --",
|
||||
"' OR '1'='1",
|
||||
"1' UNION SELECT * FROM Devices --",
|
||||
"'; INSERT INTO Events VALUES ('hacked'); --",
|
||||
"' AND (SELECT COUNT(*) FROM sqlite_master) > 0 --"
|
||||
]
|
||||
|
||||
builder = create_safe_condition_builder()
|
||||
|
||||
for malicious_input in malicious_inputs:
|
||||
condition, params = builder.get_safe_condition_legacy(malicious_input)
|
||||
# All malicious inputs should result in empty/safe condition
|
||||
self.assertEqual(condition, "", f"Malicious input not blocked: {malicious_input}")
|
||||
self.assertEqual(params, {}, f"Parameters returned for malicious input: {malicious_input}")
|
||||
|
||||
print("✅ SQL injection prevention: PASSED")
|
||||
|
||||
def test_8_error_log_inspection(self):
|
||||
"""Test 8: Error handling and logging"""
|
||||
print("\n=== TEST 8: Error Handling and Logging ===")
|
||||
|
||||
# Test that invalid inputs are logged properly
|
||||
builder = create_safe_condition_builder()
|
||||
|
||||
# This should log an error but not crash
|
||||
invalid_condition = "INVALID SQL SYNTAX HERE"
|
||||
condition, params = builder.get_safe_condition_legacy(invalid_condition)
|
||||
|
||||
# Should return empty/safe values
|
||||
self.assertEqual(condition, "")
|
||||
self.assertEqual(params, {})
|
||||
|
||||
# Test edge cases
|
||||
edge_cases = [
|
||||
None, # This would cause TypeError in unpatched version
|
||||
"",
|
||||
" ",
|
||||
"\n\t",
|
||||
"AND column_not_in_whitelist = 'value'"
|
||||
]
|
||||
|
||||
for case in edge_cases:
|
||||
try:
|
||||
if case is not None:
|
||||
condition, params = builder.get_safe_condition_legacy(case)
|
||||
self.assertIsInstance(condition, str)
|
||||
self.assertIsInstance(params, dict)
|
||||
except Exception as e:
|
||||
# Should not crash on any input
|
||||
self.fail(f"Unexpected exception for input {case}: {e}")
|
||||
|
||||
print("✅ Error handling and logging: PASSED")
|
||||
|
||||
def test_9_backward_compatibility(self):
|
||||
"""Test 9: Backward compatibility with legacy settings"""
|
||||
print("\n=== TEST 9: Backward Compatibility ===")
|
||||
|
||||
# Test legacy {s-quote} placeholder support
|
||||
builder = create_safe_condition_builder()
|
||||
|
||||
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
test/integration/test_sql_injection_fix.py
Executable file
139
test/integration/test_sql_injection_fix.py
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/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)
|
||||
0
test/test_safe_builder_unit.py
Normal file → Executable file
0
test/test_safe_builder_unit.py
Normal file → Executable file
0
test/test_sql_injection_prevention.py
Normal file → Executable file
0
test/test_sql_injection_prevention.py
Normal file → Executable file
0
test/test_sql_security.py
Normal file → Executable file
0
test/test_sql_security.py
Normal file → Executable file
Reference in New Issue
Block a user