Skip to content

Commit 3742680

Browse files
committed
fix(rest-api): warn about disabled auth at server startup, not just the CLI
The exposed-without-token warning lived only in main(), so a non-CLI launch (uvicorn/gunicorn --factory) that binds a public interface without a token got a silently world-open API with no warning. Move it into create_app()'s lifespan startup so it fires for every launch path. create_app() can't see the bind host under a factory launch, so the check is host-agnostic (warn whenever no token is configured) — a single calm log line, harmless on loopback, and silent in the unit suite (tests don't enter the TestClient context manager, so lifespan never runs there).
1 parent 8ced237 commit 3742680

1 file changed

Lines changed: 14 additions & 15 deletions

File tree

openkb/api.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44

55
import argparse
66
import asyncio
7+
import logging
78
import os
8-
import sys
99
from contextlib import asynccontextmanager
1010
from typing import Any
1111

@@ -96,6 +96,8 @@
9696
from openkb.log import append_log
9797
from openkb.watch_service import WatchRegistry
9898

99+
logger = logging.getLogger(__name__)
100+
99101

100102
def create_app() -> FastAPI:
101103
# One registry per app instance so each TestClient is isolated.
@@ -125,6 +127,17 @@ def _kb_mutation_lock(kb: str) -> asyncio.Lock:
125127

126128
@asynccontextmanager
127129
async def lifespan(app: FastAPI):
130+
# Auth is opt-in (see require_bearer_token). Warn once at server startup
131+
# when no token is configured, so an exposed deployment is never
132+
# silently world-open. Fires for every launch path (uvicorn/gunicorn/
133+
# the openkb-api CLI); harmless on loopback. (create_app() can't see the
134+
# bind host under a factory launch, so this is host-agnostic.)
135+
if not os.environ.get("OPENKB_API_TOKEN"):
136+
logger.warning(
137+
"OPENKB_API_TOKEN is not set — the REST API is unauthenticated. "
138+
"This is fine for local use; set OPENKB_API_TOKEN to require a "
139+
"bearer token before exposing the server on a reachable interface."
140+
)
128141
try:
129142
yield
130143
finally:
@@ -563,20 +576,6 @@ def main() -> None:
563576
parser.add_argument("--reload", action="store_true")
564577
args = parser.parse_args()
565578

566-
# Auth is opt-in (see require_bearer_token). That's fine on loopback, but
567-
# warn loudly if the server is bound to a reachable interface without a
568-
# token — otherwise the API (and any KB it can touch) is world-open.
569-
if not os.environ.get("OPENKB_API_TOKEN") and args.host not in {
570-
"127.0.0.1",
571-
"localhost",
572-
"::1",
573-
}:
574-
print(
575-
f"WARNING: OPENKB_API_TOKEN is not set — the REST API is UNAUTHENTICATED "
576-
f"and reachable on {args.host}. Set OPENKB_API_TOKEN to require a bearer token.",
577-
file=sys.stderr,
578-
)
579-
580579
import uvicorn
581580

582581
# Use the factory so uvicorn can reload a fresh app instance and so the

0 commit comments

Comments
 (0)