CodeEvaluator / test /test_multifile.py
DhyandevP's picture
security: military-grade archive hardening with extension allowlist
35755b6
Raw History Blame Contribute Delete
5.72 kB
"""
Smoke-tests for the multi-file processing utilities in main.py.
These tests run WITHOUT starting the server (no CUSTOM_API_KEY needed)
by importing the utilities directly after patching the environment.
"""
import io
import os
import zipfile
import tarfile
import sys
# Patch env so main.py doesn't explode on import
os.environ.setdefault("CUSTOM_API_KEY", "test-key-for-ci")
os.environ.setdefault("OPENROUTER_API_KEY", "test-key-for-ci")
# Add parent to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from main import (
_is_skippable_path,
_safe_decode,
_build_directory_tree,
_build_project_representation,
_normalize_archive_path,
_strip_common_prefix,
_extract_zip,
_extract_tar,
)
def test_is_skippable_path():
# Skip hidden dirs
assert _is_skippable_path(".git/config") is True
assert _is_skippable_path(".env") is True
# Skip known dirs
assert _is_skippable_path("node_modules/express/index.js") is True
assert _is_skippable_path("__pycache__/mod.cpython-311.pyc") is True
# Skip binary extensions (not on CODE_EXTENSIONS allowlist)
assert _is_skippable_path("assets/logo.png") is True
assert _is_skippable_path("build/app.exe") is True
# Skip unknown extensions (not on allowlist)
assert _is_skippable_path("data/file.xyz") is True
assert _is_skippable_path("archive.tar.gz") is True
# Allow code files (on allowlist)
assert _is_skippable_path("src/main.py") is False
assert _is_skippable_path("index.js") is False
assert _is_skippable_path("README.md") is False
assert _is_skippable_path("styles.css") is False
assert _is_skippable_path("app.java") is False
assert _is_skippable_path("config.yaml") is False
# Allow extension-less files (Makefile, Dockerfile, Procfile)
assert _is_skippable_path("Makefile") is False
assert _is_skippable_path("Dockerfile") is False
assert _is_skippable_path("src/Procfile") is False
print(" ✅ _is_skippable_path")
def test_safe_decode():
# Normal UTF-8
assert _safe_decode(b"hello world") == "hello world"
# Binary (null bytes) → None
assert _safe_decode(b"hello\x00world") is None
# Invalid UTF-8 with replacement
result = _safe_decode(b"hello \xff world")
assert result is not None
assert "hello" in result
print(" ✅ _safe_decode")
def test_normalize_archive_path():
assert _normalize_archive_path("src/main.py") == "src/main.py"
assert _normalize_archive_path("./src/main.py") == "src/main.py"
# Traversal attacks
assert _normalize_archive_path("../../../etc/passwd") is None
assert _normalize_archive_path("/etc/passwd") is None
# Windows paths
assert _normalize_archive_path("src\\main.py") == "src/main.py"
print(" ✅ _normalize_archive_path")
def test_build_directory_tree():
paths = ["src/index.js", "src/utils.js", "package.json"]
tree = _build_directory_tree(paths)
assert "src/" in tree
assert "index.js" in tree
assert "utils.js" in tree
assert "package.json" in tree
print(" ✅ _build_directory_tree")
print(f" Tree output:\n{tree}")
def test_build_project_representation():
file_map = {
"src/index.js": "console.log('hi');",
"package.json": '{"name": "test"}',
}
result = _build_project_representation(file_map)
assert "[PROJECT DIRECTORY TREE]" in result
assert '<FILE path="src/index.js">' in result
assert '<FILE path="package.json">' in result
assert "console.log('hi');" in result
print(" ✅ _build_project_representation")
def test_strip_common_prefix():
# With common prefix
fm = {"myproject/src/a.py": "a", "myproject/src/b.py": "b"}
stripped = _strip_common_prefix(fm)
assert "a.py" in stripped or "src/a.py" in stripped
# Without common prefix
fm2 = {"src/a.py": "a", "lib/b.py": "b"}
stripped2 = _strip_common_prefix(fm2)
assert "src/a.py" in stripped2
print(" ✅ _strip_common_prefix")
def test_extract_zip():
# Build a zip in memory
buf = io.BytesIO()
with zipfile.ZipFile(buf, "w") as zf:
zf.writestr("project/src/main.py", "print('hello')")
zf.writestr("project/src/utils.py", "def add(a, b): return a + b")
zf.writestr("project/README.md", "# My Project")
# Binary file — should be skipped
zf.writestr("project/logo.png", b"\x89PNG\r\n\x1a\n\x00\x00".decode("latin-1"))
result = _extract_zip(buf.getvalue())
assert "src/main.py" in result
assert "src/utils.py" in result
assert "README.md" in result
# .png should be skipped
assert "logo.png" not in result
print(f" ✅ _extract_zip — extracted {len(result)} files")
def test_extract_tar():
buf = io.BytesIO()
with tarfile.open(fileobj=buf, mode="w:gz") as tf:
for name, content in [
("project/app.py", "import flask"),
("project/config.yaml", "debug: true"),
]:
data = content.encode("utf-8")
info = tarfile.TarInfo(name=name)
info.size = len(data)
tf.addfile(info, io.BytesIO(data))
result = _extract_tar(buf.getvalue())
assert "app.py" in result
assert "config.yaml" in result
print(f" ✅ _extract_tar — extracted {len(result)} files")
if __name__ == "__main__":
print("\n🧪 Running multi-file utility tests...\n")
test_is_skippable_path()
test_safe_decode()
test_normalize_archive_path()
test_build_directory_tree()
test_build_project_representation()
test_strip_common_prefix()
test_extract_zip()
test_extract_tar()
print("\n✅ All tests passed!\n")