90 lines
2.3 KiB
Python
90 lines
2.3 KiB
Python
from __future__ import annotations
|
|
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def read_project_file(name: str) -> str:
|
|
return (PROJECT_ROOT / name).read_text(encoding="utf-8")
|
|
|
|
|
|
def requirement_names(text: str) -> set[str]:
|
|
names: set[str] = set()
|
|
|
|
for raw_line in text.splitlines():
|
|
line = raw_line.strip()
|
|
if not line or line.startswith(("#", "-r")):
|
|
continue
|
|
|
|
match = re.match(r"([A-Za-z0-9_.-]+)", line)
|
|
if match:
|
|
names.add(match.group(1).casefold().replace("_", "-"))
|
|
|
|
return names
|
|
|
|
|
|
def test_no_development_secret_is_committed_in_runtime_config() -> None:
|
|
files = [
|
|
read_project_file("docker-compose.yml"),
|
|
read_project_file("app/main.py"),
|
|
]
|
|
|
|
assert all("dev-secret" not in text for text in files)
|
|
|
|
|
|
def test_compose_uses_env_file_and_keeps_chunk_configuration() -> None:
|
|
compose = read_project_file("docker-compose.yml")
|
|
|
|
assert "env_file:" in compose
|
|
assert ".env" in compose
|
|
assert "CHUNK_MAX_TOKENS" in compose
|
|
assert "CHUNK_OVERLAP_TOKENS" in compose
|
|
assert "CHUNK_MIN_TOKENS" in compose
|
|
assert "CHUNK_TOKEN_ENCODING" in compose
|
|
assert "./data:/app/data" in compose
|
|
assert "../zpwiki:/zpwiki" in compose
|
|
|
|
|
|
def test_secrets_are_ignored_by_git_and_docker() -> None:
|
|
gitignore = read_project_file(".gitignore")
|
|
dockerignore = read_project_file(".dockerignore")
|
|
|
|
assert re.search(r"(?m)^\.env$", gitignore)
|
|
assert re.search(r"(?m)^\.env$", dockerignore)
|
|
|
|
|
|
def test_runtime_requirements_contain_only_direct_dependencies() -> None:
|
|
names = requirement_names(read_project_file("requirements.txt"))
|
|
|
|
required = {
|
|
"fastapi",
|
|
"pydantic",
|
|
"python-frontmatter",
|
|
"rich",
|
|
"tiktoken",
|
|
"uvicorn",
|
|
}
|
|
forbidden = {
|
|
"gitpython",
|
|
"gitdb",
|
|
"smmap",
|
|
"starlette",
|
|
"pydantic-core",
|
|
"annotated-types",
|
|
}
|
|
|
|
assert required <= names
|
|
assert names.isdisjoint(forbidden)
|
|
|
|
|
|
def test_all_application_python_files_compile() -> None:
|
|
targets = [PROJECT_ROOT / "app", PROJECT_ROOT / "scripts"]
|
|
|
|
for directory in targets:
|
|
for path in directory.rglob("*.py"):
|
|
source = path.read_text(encoding="utf-8")
|
|
compile(source, str(path), "exec")
|