"""
Security-focused tests for DMARQ application.
Covers API key management, domain validation, file upload limits, and XML parsing security.
"""
import pytest
from app.core.security import add_api_key, generate_api_key, verify_api_key
from app.services.dmarc_parser import DMARCParser
from app.utils.domain_validator import validate_domain, validate_domain_config
class TestAPIKeySecurity:
"""Test API key generation and verification."""
def test_generate_api_key_length_and_uniqueness(self):
"""Generated keys should be 64 hex characters and unique."""
key1 = generate_api_key()
key2 = generate_api_key()
assert len(key1) == 64
assert len(key2) == 64
assert key1 != key2
assert all(c in "0123456789abcdef" for c in key1)
def test_add_and_verify_api_key(self):
"""Keys should only be valid after being added."""
key = generate_api_key()
assert not verify_api_key(key)
assert add_api_key(key) is True
assert verify_api_key(key) is True
# Adding the same key again returns False
assert add_api_key(key) is False
class TestDomainValidation:
"""Test domain name validation."""
@pytest.mark.parametrize(
"domain",
[
"example.com",
"subdomain.example.com",
"my-domain.example.org",
"test123.example.net",
],
)
def test_valid_domains(self, domain):
is_valid, error, _ = validate_domain(domain, check_dns=False)
assert is_valid, f"Domain {domain} should be valid: {error}"
@pytest.mark.parametrize(
"domain",
[
"",
" ",
"example",
"-example.com",
"example-.com",
"exam ple.com",
"example..com",
"a" * 64 + ".com",
"a" * 254,
],
)
def test_invalid_domain_format(self, domain):
is_valid, error, _ = validate_domain(domain, check_dns=False)
assert not is_valid, f"Domain '{domain}' should be invalid"
assert error is not None
@pytest.mark.parametrize(
"domain",
[
"example.com"}
)
assert not result["valid"]
assert "description" in result["errors"]
class TestFileUploadSecurity:
"""Test file upload size limits."""
def test_file_size_limit(self):
large_content = b"x" * (11 * 1024 * 1024)
with pytest.raises(ValueError, match="too large"):
DMARCParser.parse_file(large_content, "test.xml")
class TestXMLParsingSecurity:
"""Test XML parsing security (defusedxml, XXE protection)."""
def test_defusedxml_is_used(self):
import app.services.dmarc_parser as parser_module
assert hasattr(parser_module, "ET")
module_info = str(getattr(parser_module.ET, "__name__", "")) + str(
getattr(parser_module.ET, "__module__", "")
)
assert "defusedxml" in module_info.lower()
def test_xxe_protection(self):
"""defusedxml should prevent XXE entity expansion."""
xxe_payload = b"""\
]>
&xxe;
"""
# defusedxml should raise an error or not expand the entity
try:
result = DMARCParser.parse_file(xxe_payload, "test.xml")
org_name = result.get("org_name", "")
assert "root:" not in org_name and "/bin" not in org_name
except Exception:
pass # Expected – defusedxml blocks DTD processing