Skip to content

Commit c18eed6

Browse files
committed
Fix lazy file validation imports
1 parent 04b5728 commit c18eed6

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

tests/unit/test_storage_validation.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33

44
import pytest
55

6+
import tracecat.storage.validation as storage_validation
67
from tracecat.storage.exceptions import (
8+
FileContentMismatchError,
79
FileExtensionError,
810
FileMimeTypeError,
911
FileNameError,
@@ -109,6 +111,32 @@ def test_zip_upload_passes(validator_basic: FileSecurityValidator) -> None:
109111
assert validation_result.content_type == "application/zip"
110112

111113

114+
def test_missing_polyfile_dependency_raises_generic_message(
115+
monkeypatch: pytest.MonkeyPatch,
116+
validator_basic: FileSecurityValidator,
117+
) -> None:
118+
monkeypatch.setattr(storage_validation, "_MAGIC_MATCHER", None)
119+
real_import_module = storage_validation.importlib.import_module
120+
121+
def fake_import_module(name: str, package: str | None = None) -> object:
122+
if name == "polyfile.magic":
123+
raise ModuleNotFoundError("No module named 'chardet.universaldetector'")
124+
return real_import_module(name, package)
125+
126+
monkeypatch.setattr(
127+
storage_validation.importlib, "import_module", fake_import_module
128+
)
129+
130+
with pytest.raises(FileContentMismatchError) as exc:
131+
validator_basic.validate_file(
132+
content=pdf_bytes(),
133+
filename="doc.pdf",
134+
declared_mime_type="application/pdf",
135+
)
136+
137+
assert str(exc.value) == "Unknown or unsupported file type"
138+
139+
112140
@pytest.mark.parametrize(
113141
"filename",
114142
[

tracecat/storage/validation.py

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,11 @@
1414
https://cheatsheetseries.owasp.org/cheatsheets/File_Upload_Cheat_Sheet.html#list-allowed-extensions
1515
"""
1616

17+
import importlib
1718
import os
1819
from collections.abc import Sequence
20+
from typing import Any
1921

20-
from polyfile.magic import MagicMatcher
2122
from pydantic import BaseModel
2223

2324
from tracecat import config
@@ -30,6 +31,16 @@
3031
FileSizeError,
3132
)
3233

34+
_MAGIC_MATCHER: Any | None = None
35+
36+
37+
def _get_magic_matcher() -> Any:
38+
global _MAGIC_MATCHER
39+
if _MAGIC_MATCHER is None:
40+
polyfile_magic = importlib.import_module("polyfile.magic")
41+
_MAGIC_MATCHER = polyfile_magic.MagicMatcher.DEFAULT_INSTANCE
42+
return _MAGIC_MATCHER
43+
3344

3445
class FileValidationResult(BaseModel):
3546
"""Result of file validation."""
@@ -207,7 +218,7 @@ def _validate_magic_number(self, content: bytes, declared_mime_type: str) -> boo
207218
detected_equiv: set[str] = set()
208219

209220
try:
210-
matches = list(MagicMatcher.DEFAULT_INSTANCE.match(content))
221+
matches = list(_get_magic_matcher().match(content))
211222
for match in matches:
212223
mimetypes = getattr(match, "mimetypes", None)
213224
if mimetypes:

0 commit comments

Comments
 (0)