Bladeren bron

feat(oidc): apply the env provider during startup

Placed after init_db(): is_env_managed only exists once run_migrations has
added it, so an upsert before that would fail on every existing installation.

The wiring gets its own tests because the apply tests cannot cover it -- they
call apply_env_oidc_provider() directly, so deleting this call would leave the
feature dead with a fully green suite. Verified: removing the call fails the
three startup tests while all seven apply tests still pass.

They assert against the lifespan's source rather than running it. The function
is ~460 lines and starts printer connections, MQTT and schedulers; executing
it would exercise everything except the line in question. The docstring says
plainly that this proves the call exists and runs after migrations, and
proves nothing about its behaviour.

Refs #2593
Marian 1 maand geleden
bovenliggende
commit
e7a413e745
2 gewijzigde bestanden met toevoegingen van 51 en 0 verwijderingen
  1. 8 0
      backend/app/main.py
  2. 43 0
      backend/tests/integration/test_oidc_env_startup.py

+ 8 - 0
backend/app/main.py

@@ -6194,6 +6194,14 @@ async def lifespan(app: FastAPI):
 
     await init_db()
 
+    # After migrations, so the is_env_managed column exists. Never raises --
+    # a bad BAMBUDDY_OIDC_* value is logged and skipped rather than blocking
+    # startup (see apply_env_oidc_provider).
+    from backend.app.core.oidc_env import apply_env_oidc_provider
+
+    async with async_session() as oidc_db:
+        await apply_env_oidc_provider(oidc_db)
+
     # Register an app-scoped httpx client for Bambu Cloud services so
     # per-request BambuCloudService instances reuse the same connection pool
     # (important for routes like /cloud/filament-info that chain many

+ 43 - 0
backend/tests/integration/test_oidc_env_startup.py

@@ -0,0 +1,43 @@
+"""The env provider is applied on startup, not merely appliable (#2593).
+
+test_oidc_env_apply.py calls apply_env_oidc_provider() directly, so it stays
+green even if nothing ever calls it -- deleting the lifespan call would leave
+the feature dead with a fully passing suite. These tests pin the call site.
+
+They read the lifespan's source rather than running it: the function is ~460
+lines and starts printer connections, MQTT and schedulers, so executing it
+here would test everything except the one line in question. That makes this a
+wiring check, not a behavioural one -- it proves the call exists and runs
+after migrations, and deliberately proves nothing about what it does. The
+behaviour is covered by test_oidc_env_apply.py.
+"""
+
+from __future__ import annotations
+
+import inspect
+
+from backend.app.main import lifespan
+
+
+def _lifespan_source() -> str:
+    return inspect.getsource(lifespan)
+
+
+def test_lifespan_applies_the_env_oidc_provider():
+    assert "apply_env_oidc_provider(" in _lifespan_source()
+
+
+def test_it_runs_after_the_migrations():
+    """is_env_managed does not exist until run_migrations has added it, so an
+    upsert before init_db() would fail on every existing installation."""
+    source = _lifespan_source()
+    assert source.index("await init_db()") < source.index("apply_env_oidc_provider(")
+
+
+def test_the_apply_call_is_awaited():
+    """apply_env_oidc_provider is a coroutine; calling it without await would
+    return an un-awaited coroutine and silently apply nothing."""
+    source = _lifespan_source()
+    call = source.index("apply_env_oidc_provider(")
+    line_start = source.rindex("\n", 0, call) + 1
+    assert source[line_start:call].strip().endswith("await")