mirror of
http://100.103.83.12:3003/fegger/odoo-at-payroll.git
synced 2026-09-17 16:56:42 +00:00
feat(agent): add test frontend and Docker stack
This commit is contained in:
@@ -69,6 +69,32 @@ def configure_state(*, api_key: str = "", admin_key: str = "") -> None:
|
||||
app.state.rag.retriever = FakeRetriever()
|
||||
|
||||
|
||||
def test_frontend_is_served_with_security_headers():
|
||||
with TestClient(app) as client:
|
||||
configure_state(api_key="service-secret")
|
||||
response = client.get("/")
|
||||
assert response.status_code == 200
|
||||
assert "PV Wissen" in response.text
|
||||
assert "service-secret" not in response.text
|
||||
assert response.headers["cache-control"] == "no-store"
|
||||
assert response.headers["x-frame-options"] == "DENY"
|
||||
assert response.headers["x-content-type-options"] == "nosniff"
|
||||
assert "script-src 'self'" in response.headers["content-security-policy"]
|
||||
|
||||
|
||||
def test_frontend_assets_use_v1_api_and_unknown_assets_are_hidden():
|
||||
with TestClient(app) as client:
|
||||
configure_state()
|
||||
script = client.get("/assets/app.js")
|
||||
styles = client.get("/assets/styles.css")
|
||||
missing = client.get("/assets/index.html")
|
||||
assert script.status_code == 200
|
||||
assert styles.status_code == 200
|
||||
assert 'fetch("/v1/ask"' in script.text
|
||||
assert "innerHTML" not in script.text
|
||||
assert missing.status_code == 404
|
||||
|
||||
|
||||
def test_nonlocal_bind_without_api_key_is_rejected(capsys):
|
||||
class Args:
|
||||
host = "0.0.0.0"
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
"""Statische Schutztests für den Docker-Compose-Deploymentvertrag."""
|
||||
from pathlib import Path
|
||||
|
||||
import yaml
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
|
||||
|
||||
def load_compose() -> dict:
|
||||
return yaml.safe_load((ROOT / "compose.yaml").read_text(encoding="utf-8"))
|
||||
|
||||
|
||||
def test_compose_uses_external_ollama_network_and_tailscale_bind():
|
||||
compose = load_compose()
|
||||
service = compose["services"]["pv-agent"]
|
||||
assert service["networks"] == ["ollama-default"]
|
||||
assert compose["networks"]["ollama-default"] == {
|
||||
"external": True,
|
||||
"name": "ollama-default",
|
||||
}
|
||||
assert "100.103.83.12:${PV_PORT:-8080}:8080" in service["ports"]
|
||||
assert service["environment"]["OLLAMA_URL"] == (
|
||||
"${OLLAMA_URL:-http://ollama:11434}"
|
||||
)
|
||||
|
||||
|
||||
def test_compose_requires_auth_and_limits_container_privileges():
|
||||
service = load_compose()["services"]["pv-agent"]
|
||||
assert ":?" in service["environment"]["PV_API_KEY"]
|
||||
assert "env_file" not in service
|
||||
assert service["read_only"] is True
|
||||
assert service["security_opt"] == ["no-new-privileges:true"]
|
||||
assert service["cap_drop"] == ["ALL"]
|
||||
assert "./data:/app/data" in service["volumes"]
|
||||
assert "./wissensbasis:/app/wissensbasis:ro" in service["volumes"]
|
||||
|
||||
|
||||
def test_docker_context_excludes_secrets_and_runtime_data():
|
||||
ignored = set(
|
||||
(ROOT / ".dockerignore").read_text(encoding="utf-8").splitlines()
|
||||
)
|
||||
assert {".env", "data", ".lexis360", ".rechtsprechung", "wissensbasis"} <= ignored
|
||||
dockerfile = (ROOT / "Dockerfile").read_text(encoding="utf-8")
|
||||
assert "requirements-runtime.txt" in dockerfile
|
||||
assert "COPY agent/" in dockerfile
|
||||
assert "COPY web/" in dockerfile
|
||||
assert "COPY ." not in dockerfile
|
||||
Reference in New Issue
Block a user