GitHub Actions commited on
Commit
3624fdd
·
1 Parent(s): 3e811b0

Deploy backend from GitHub 6595772e2155cd1a17c0a6783d580c6b9f4f4245

Browse files
backend/app/core/config.py CHANGED
@@ -11,12 +11,14 @@ _HF_ROUTER = "https://router.huggingface.co/hf-inference/models"
11
 
12
 
13
  class Settings(BaseSettings):
14
- APP_NAME: str = "LLM Misuse Detector"
15
  DEBUG: bool = False
16
 
17
  # Firebase
18
  FIREBASE_PROJECT_ID: str = ""
19
  FIREBASE_CREDENTIALS_JSON: Optional[str] = None
 
 
20
 
21
  # Redis
22
  REDIS_URL: str = "redis://localhost:6379/0"
 
11
 
12
 
13
  class Settings(BaseSettings):
14
+ APP_NAME: str = "Zynera"
15
  DEBUG: bool = False
16
 
17
  # Firebase
18
  FIREBASE_PROJECT_ID: str = ""
19
  FIREBASE_CREDENTIALS_JSON: Optional[str] = None
20
+ # Set to False to skip Firestore init at startup (useful when credentials are absent)
21
+ FIRESTORE_AUTO_INIT: bool = True
22
 
23
  # Redis
24
  REDIS_URL: str = "redis://localhost:6379/0"
backend/app/main.py CHANGED
@@ -37,8 +37,11 @@ REQUEST_LATENCY = Histogram("http_request_duration_seconds", "Request latency",
37
 
38
  @asynccontextmanager
39
  async def lifespan(app: FastAPI):
40
- logger.info("Starting LLM Misuse Detection API")
41
- init_firebase()
 
 
 
42
  yield
43
  logger.info("Shutting down")
44
 
@@ -46,7 +49,7 @@ async def lifespan(app: FastAPI):
46
  app = FastAPI(
47
  title=settings.APP_NAME,
48
  version="1.0.0",
49
- description="Production system for detecting and mitigating LLM misuse in information operations",
50
  lifespan=lifespan,
51
  )
52
 
 
37
 
38
  @asynccontextmanager
39
  async def lifespan(app: FastAPI):
40
+ logger.info("Starting Zynera API")
41
+ if settings.FIRESTORE_AUTO_INIT:
42
+ init_firebase()
43
+ else:
44
+ logger.info("Firestore auto-init disabled (FIRESTORE_AUTO_INIT=false) – skipping")
45
  yield
46
  logger.info("Shutting down")
47
 
 
49
  app = FastAPI(
50
  title=settings.APP_NAME,
51
  version="1.0.0",
52
+ description="Zynera AI-powered detection of LLM misuse in information operations",
53
  lifespan=lifespan,
54
  )
55
 
backend/tests/test_api.py CHANGED
@@ -27,6 +27,42 @@ def client():
27
  return c
28
 
29
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  class TestHealthEndpoint:
31
  def test_health_check(self, client):
32
  response = client.get("/health")
 
27
  return c
28
 
29
 
30
+ class TestStartupWithoutCredentials:
31
+ """Verify the server starts cleanly when no GCP/Firebase credentials are present."""
32
+
33
+ def test_health_returns_200_without_firebase_credentials(self):
34
+ """App must start and /health must return 200 even without Firebase credentials."""
35
+ # Use the same safe mock pattern as _make_client() – no real credentials needed
36
+ c, _ = _make_client()
37
+ response = c.get("/health")
38
+ assert response.status_code == 200
39
+ data = response.json()
40
+ assert data["status"] == "ok"
41
+
42
+ def test_firestore_auto_init_false_skips_init(self):
43
+ """When FIRESTORE_AUTO_INIT is False, init_firebase must not be invoked at startup."""
44
+ from backend.app.main import app as _app
45
+ from backend.app.core import config
46
+
47
+ original = config.settings.FIRESTORE_AUTO_INIT
48
+ try:
49
+ config.settings.FIRESTORE_AUTO_INIT = False
50
+ with patch("backend.app.db.firestore.init_firebase") as mock_init:
51
+ # Simulate a lifespan startup by calling the lifespan coroutine
52
+ import asyncio
53
+ from contextlib import asynccontextmanager
54
+
55
+ async def run_lifespan():
56
+ from backend.app.main import lifespan
57
+ async with lifespan(_app):
58
+ pass
59
+
60
+ asyncio.run(run_lifespan())
61
+ mock_init.assert_not_called()
62
+ finally:
63
+ config.settings.FIRESTORE_AUTO_INIT = original
64
+
65
+
66
  class TestHealthEndpoint:
67
  def test_health_check(self, client):
68
  response = client.get("/health")