sciagent code + Gitea Actions CI/CD
CI/CD / backend (push) Failing after 2m8s
CI/CD / frontend (push) Failing after 1m40s
CI/CD / deploy (push) Has been skipped

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Thinh Lam
2026-06-30 09:38:30 +07:00
commit 688fac73e9
1167 changed files with 158244 additions and 0 deletions
+158
View File
@@ -0,0 +1,158 @@
"""
Security regression tests for authenticated / removed routes (no Postgres required).
Run: cd be0 && python -m unittest tests.test_security_routes -v
"""
from __future__ import annotations
import os
import unittest
from unittest.mock import patch
from tests.security_token_fixture import mint_bearer_token
class SecurityRoutesTests(unittest.TestCase):
def _client(self):
from fastapi.testclient import TestClient
from main import app
return TestClient(app)
def test_removed_upload_document_returns_404(self) -> None:
client = self._client()
r = client.post("/upload_document", files={"file": ("x.pdf", b"%PDF", "application/pdf")})
self.assertEqual(r.status_code, 404)
def test_removed_get_page_returns_404(self) -> None:
client = self._client()
r = client.post("/get_page", data={"new_page_number": "1"})
self.assertEqual(r.status_code, 404)
def test_list_applications_requires_auth(self) -> None:
client = self._client()
r = client.get("/api/applications")
self.assertEqual(r.status_code, 401)
def test_list_applications_rejects_viewer(self) -> None:
client = self._client()
headers = {"Authorization": mint_bearer_token(roles=("viewer",))}
with patch("src.initiative_db.engine.is_postgres_enabled", return_value=False):
r = client.get("/api/applications", headers=headers)
self.assertEqual(r.status_code, 403)
def test_list_applications_allows_staff_without_db(self) -> None:
client = self._client()
headers = {"Authorization": mint_bearer_token(roles=("admin",))}
with patch("src.initiative_db.engine.is_postgres_enabled", return_value=False):
with patch("main._load_submitted_items", return_value=[]):
r = client.get("/api/applications", headers=headers)
self.assertEqual(r.status_code, 200, r.text)
self.assertIn("data", r.json())
def test_get_application_requires_auth(self) -> None:
client = self._client()
r = client.get("/api/applications/sub-deadbeefdeadbeef")
self.assertEqual(r.status_code, 401)
def test_get_application_rejects_viewer_without_row(self) -> None:
client = self._client()
headers = {"Authorization": mint_bearer_token(roles=("viewer",), email="viewer@ump.edu.vn")}
with patch("src.initiative_db.engine.is_postgres_enabled", return_value=False):
with patch("main._get_application_from_file_index", return_value=None):
r = client.get("/api/applications/sub-deadbeefdeadbeef", headers=headers)
self.assertEqual(r.status_code, 404)
def test_review_documents_list_requires_auth(self) -> None:
client = self._client()
r = client.get("/api/v1/review-documents", params={"caseId": "CASE-1"})
self.assertEqual(r.status_code, 401)
def test_review_documents_create_requires_auth(self) -> None:
client = self._client()
r = client.post(
"/api/v1/review-documents",
json={"caseId": "CASE-1", "officialBieuMau": {}},
)
self.assertEqual(r.status_code, 401)
def test_chat_requires_auth(self) -> None:
client = self._client()
r = client.post("/api/v1/chat", json={"message": "hello"})
self.assertEqual(r.status_code, 401)
def test_analyze_compliance_requires_auth(self) -> None:
client = self._client()
r = client.post(
"/analyze_compliance",
json={"external_requirements": ["ext"], "internal_requirements": ["int"]},
)
self.assertEqual(r.status_code, 401)
def test_test_ollama_requires_admin(self) -> None:
client = self._client()
viewer = {"Authorization": mint_bearer_token(roles=("viewer",))}
r_viewer = client.post("/test_ollama", json={"prompt": "hi"}, headers=viewer)
self.assertEqual(r_viewer.status_code, 403)
admin = {"Authorization": mint_bearer_token(roles=("admin",))}
with patch(
"main.ollama.chat",
return_value={"message": {"content": "ok"}},
):
r_admin = client.post("/test_ollama", json={"prompt": "hi"}, headers=admin)
self.assertEqual(r_admin.status_code, 200, r_admin.text)
def test_ideas_post_requires_admin(self) -> None:
client = self._client()
headers = {"Authorization": mint_bearer_token(roles=("viewer",))}
r = client.post(
"/api/v1/ideas",
json={"title": "t", "description": "d"},
headers=headers,
)
self.assertEqual(r.status_code, 403)
def test_security_headers_on_health(self) -> None:
client = self._client()
r = client.get("/health")
self.assertEqual(r.status_code, 200)
self.assertEqual(r.headers.get("x-content-type-options"), "nosniff")
self.assertEqual(r.headers.get("x-frame-options"), "DENY")
self.assertIn("referrer-policy", r.headers)
class JwtSecretTests(unittest.TestCase):
def test_production_requires_secret(self) -> None:
from src.auth_jwt import jwt_secret
env = {k: v for k, v in os.environ.items() if k not in ("JWT_SECRET", "ENVIRONMENT")}
env["ENVIRONMENT"] = "production"
with patch.dict(os.environ, env, clear=True):
with self.assertRaises(RuntimeError):
jwt_secret()
def test_development_allows_dev_fallback(self) -> None:
from src.auth_jwt import jwt_secret
with patch.dict(os.environ, {"ENVIRONMENT": "development"}, clear=False):
os.environ.pop("JWT_SECRET", None)
secret = jwt_secret()
self.assertGreaterEqual(len(secret), 32)
class LoginRateLimitTests(unittest.TestCase):
def test_login_rate_limit_blocks_after_threshold(self) -> None:
from src.auth_rate_limit import allow_login
email = "ratelimit-test@ump.edu.vn"
ip = "203.0.113.50"
for _ in range(5):
self.assertTrue(allow_login(email, ip))
self.assertFalse(allow_login(email, ip))
if __name__ == "__main__":
unittest.main()