"""Tests for IANA data validators.""" import sqlite3 import pytest from sslysze_scan.iana_validator import ( ValidationError, get_min_rows, normalize_header, validate_cipher_suite_row, validate_headers, validate_ikev2_row, validate_registry_data, validate_signature_schemes_row, validate_supported_groups_row, ) class TestNormalizeHeader: """Tests for header normalization.""" def test_normalize_combined(self) -> None: """Test combined normalization.""" assert normalize_header("RFC/Draft") == "rfc_draft" assert normalize_header("Recommended") == "recommended" class TestValidateHeaders: """Tests for header validation against database schema.""" def test_validate_headers_matching(self, test_db_path: str) -> None: """Test that correct headers pass validation.""" conn = sqlite3.connect(test_db_path) headers = ["Value", "Description", "DTLS", "Recommended", "RFC/Draft"] validate_headers("iana_tls_cipher_suites", headers, conn) conn.close() def test_validate_headers_mismatch_count(self, test_db_path: str) -> None: """Test that wrong number of columns raises error.""" conn = sqlite3.connect(test_db_path) headers = ["Value", "Description"] with pytest.raises(ValidationError, match="Column count mismatch"): validate_headers("iana_tls_cipher_suites", headers, conn) conn.close() def test_validate_headers_mismatch_name(self, test_db_path: str) -> None: """Test that wrong column name raises error.""" conn = sqlite3.connect(test_db_path) headers = ["Value", "Name", "DTLS", "Recommended", "RFC/Draft"] with pytest.raises(ValidationError, match="Column .* mismatch"): validate_headers("iana_tls_cipher_suites", headers, conn) conn.close() class TestCipherSuiteValidation: """Tests for cipher suite data validation.""" def test_valid_cipher_suite(self) -> None: """Test that valid cipher suite passes.""" row = { "value": "0x13,0x01", "description": "TLS_AES_128_GCM_SHA256", "dtls": "Y", "recommended": "Y", "rfc_draft": "rfc: rfc8446", } validate_cipher_suite_row(row) def test_missing_required_field(self) -> None: """Test that missing value field raises error.""" row = {"description": "TLS_AES_128_GCM_SHA256"} with pytest.raises(ValidationError, match="Missing required field"): validate_cipher_suite_row(row) def test_invalid_value_format(self) -> None: """Test that invalid value format raises error.""" row = { "value": "1301", "description": "TLS_AES_128_GCM_SHA256", } with pytest.raises(ValidationError, match="Invalid value format"): validate_cipher_suite_row(row) def test_invalid_recommended_value(self) -> None: """Test that invalid Recommended value raises error.""" row = { "value": "0x13,0x01", "description": "TLS_AES_128_GCM_SHA256", "recommended": "X", } with pytest.raises(ValidationError, match="Invalid Recommended value"): validate_cipher_suite_row(row) def test_empty_recommended_valid(self) -> None: """Test that empty Recommended field is valid.""" row = { "value": "0x13,0x01", "description": "TLS_AES_128_GCM_SHA256", "recommended": "", } validate_cipher_suite_row(row) class TestSupportedGroupsValidation: """Tests for supported groups data validation.""" def test_valid_supported_group(self) -> None: """Test that valid supported group passes.""" row = { "value": "23", "description": "secp256r1", "recommended": "Y", } validate_supported_groups_row(row) def test_invalid_value_non_numeric(self) -> None: """Test that non-numeric value raises error.""" row = {"value": "0x17", "description": "secp256r1"} with pytest.raises(ValidationError, match="Value must be numeric"): validate_supported_groups_row(row) class TestSignatureSchemesValidation: """Tests for signature schemes data validation.""" def test_valid_signature_scheme(self) -> None: """Test that valid signature scheme passes.""" row = { "value": "0x0403", "description": "ecdsa_secp256r1_sha256", "recommended": "Y", } validate_signature_schemes_row(row) def test_invalid_value_format(self) -> None: """Test that invalid value format raises error.""" row = {"value": "0403", "description": "ecdsa_secp256r1_sha256"} with pytest.raises(ValidationError, match="Invalid value format"): validate_signature_schemes_row(row) class TestIKEv2Validation: """Tests for IKEv2 data validation.""" def test_valid_ikev2_row(self) -> None: """Test that valid IKEv2 row passes.""" row = { "value": "12", "description": "ENCR_AES_CBC", "esp": "Y", "ikev2": "Y", } validate_ikev2_row(row) def test_invalid_value_non_numeric(self) -> None: """Test that non-numeric value raises error.""" row = {"value": "0x0C", "description": "ENCR_AES_CBC"} with pytest.raises(ValidationError, match="Value must be numeric"): validate_ikev2_row(row) class TestGetMinRows: """Tests for minimum row count lookup.""" def test_get_min_rows_unknown_table(self) -> None: """Test that unknown tables return default minimum.""" assert get_min_rows("iana_unknown_table") == 5 class TestValidateRegistryData: """Tests for complete registry data validation.""" def test_validate_registry_sufficient_rows(self) -> None: """Test that sufficient rows pass validation.""" rows = [ { "value": f"0x13,0x{i:02x}", "description": f"Cipher_{i}", "dtls": "Y", "recommended": "Y", "rfc_draft": "rfc: rfc8446", } for i in range(60) ] validate_registry_data("iana_tls_cipher_suites", rows) def test_validate_registry_insufficient_rows(self) -> None: """Test that insufficient rows raise error.""" rows = [ { "value": "0x13,0x01", "description": "Cipher_1", "dtls": "Y", "recommended": "Y", "rfc_draft": "rfc: rfc8446", } ] with pytest.raises(ValidationError, match="Insufficient data"): validate_registry_data("iana_tls_cipher_suites", rows) def test_validate_registry_invalid_row(self) -> None: """Test that invalid row in dataset raises error.""" rows = [ { "value": f"0x13,0x{i:02x}", "description": f"Cipher_{i}", "dtls": "Y", "recommended": "Y", "rfc_draft": "rfc: rfc8446", } for i in range(60) ] rows[30]["value"] = "invalid" with pytest.raises(ValidationError, match="Row 31"): validate_registry_data("iana_tls_cipher_suites", rows) def test_validate_registry_no_validator(self) -> None: """Test that tables without validator pass basic validation.""" rows = [{"value": "1", "description": f"Item_{i}"} for i in range(10)] validate_registry_data("iana_tls_alerts", rows)