From 2a916023e5a71f8e3672c2ddf9edcd1f4033cf4c Mon Sep 17 00:00:00 2001 From: mikemikimike <13286568797@163.com> Date: Thu, 3 Sep 2026 13:42:03 +0800 Subject: [PATCH] fix: require configured auth cookie secret --- app/api/agentops/auth/environment.py | 9 +++--- app/api/agentops/auth/views.py | 6 ++++ app/api/tests/auth/test_cookie_secret.py | 40 ++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 5 deletions(-) create mode 100644 app/api/tests/auth/test_cookie_secret.py diff --git a/app/api/agentops/auth/environment.py b/app/api/agentops/auth/environment.py index b7b2fd604..6b3a27d46 100644 --- a/app/api/agentops/auth/environment.py +++ b/app/api/agentops/auth/environment.py @@ -1,10 +1,9 @@ import os from agentops.api.log_config import logger -# generate an AUTH_COOKIE_SECRET with: +# Generate an AUTH_COOKIE_SECRET with: # import secrets; print(secrets.token_hex(32)) -_DEV_AUTH_COOKIE_SECRET = "your_cookie_signing_secret" -AUTH_COOKIE_SECRET = os.getenv("AUTH_COOKIE_SECRET", _DEV_AUTH_COOKIE_SECRET) +AUTH_COOKIE_SECRET: str | None = os.getenv("AUTH_COOKIE_SECRET") AUTH_COOKIE_NAME = os.getenv("AUTH_COOKIE_NAME", "session_id") AUTH_JWT_ALGO = "HS256" # this is for our internal JWT on the session cookie @@ -24,8 +23,8 @@ SUPABASE_JWT_SECRET: str = os.getenv("JWT_SECRET_KEY") -if AUTH_COOKIE_SECRET == _DEV_AUTH_COOKIE_SECRET: - logger.warning("[agentops.auth.environment] Using an unsafe AUTH_COOKIE_SECRET") +if not AUTH_COOKIE_SECRET: + logger.error("[agentops.auth.environment] AUTH_COOKIE_SECRET is not configured") if not SUPABASE_JWT_SECRET: logger.warning("[agentops.auth.environment] No JWT_SECRET_KEY set") diff --git a/app/api/agentops/auth/views.py b/app/api/agentops/auth/views.py index cc502b6d0..049803366 100644 --- a/app/api/agentops/auth/views.py +++ b/app/api/agentops/auth/views.py @@ -143,6 +143,9 @@ def _encode_session_cookie(session: Session) -> str: Currently this just includes the session_id in order to avoid storing any sensitive information in the cookie. """ + if not AUTH_COOKIE_SECRET: + raise AuthException("AUTH_COOKIE_SECRET environment variable is not configured.") + session_id = str(session.session_id) return jwt.encode({"session_id": session_id}, AUTH_COOKIE_SECRET, algorithm=AUTH_JWT_ALGO) @@ -153,6 +156,9 @@ def _decode_session_cookie(cookie: str) -> Session | None: Raises AuthException if the cookie is invalid or expired. Returns None if the session is not found. """ + if not AUTH_COOKIE_SECRET: + raise AuthException("AUTH_COOKIE_SECRET environment variable is not configured.") + try: data = jwt.decode(cookie, AUTH_COOKIE_SECRET, algorithms=[AUTH_JWT_ALGO]) return Session.get(data['session_id']) diff --git a/app/api/tests/auth/test_cookie_secret.py b/app/api/tests/auth/test_cookie_secret.py new file mode 100644 index 000000000..27b4b7569 --- /dev/null +++ b/app/api/tests/auth/test_cookie_secret.py @@ -0,0 +1,40 @@ +"""Regression tests for required session-cookie signing configuration.""" + +from uuid import uuid4 + +import jwt +import pytest + +from agentops.auth import environment +from agentops.auth import views +from agentops.auth.exceptions import AuthException +from agentops.auth.session import Session + + +def test_missing_cookie_secret_has_no_committed_fallback(monkeypatch): + """Cookie signing must fail closed when AUTH_COOKIE_SECRET is absent.""" + monkeypatch.delenv("AUTH_COOKIE_SECRET", raising=False) + monkeypatch.setattr(environment, "AUTH_COOKIE_SECRET", None) + monkeypatch.setattr(views, "AUTH_COOKIE_SECRET", None) + + assert environment.AUTH_COOKIE_SECRET != "your_cookie_signing_secret" + session = Session(session_id=uuid4(), user_id=uuid4()) + + with pytest.raises(AuthException, match="AUTH_COOKIE_SECRET"): + views._encode_session_cookie(session) + with pytest.raises(AuthException, match="AUTH_COOKIE_SECRET"): + views._decode_session_cookie("not-a-token") + + +def test_configured_cookie_secret_signs_and_verifies_session_cookie(monkeypatch): + """A deployment-provided secret continues to support cookie authentication.""" + secret = "test-only-cookie-secret" + monkeypatch.setattr(views, "AUTH_COOKIE_SECRET", secret) + session = Session(session_id=uuid4(), user_id=uuid4()) + monkeypatch.setattr(Session, "get", classmethod(lambda cls, session_id: session)) + + token = views._encode_session_cookie(session) + + decoded = jwt.decode(token, secret, algorithms=[views.AUTH_JWT_ALGO]) + assert decoded["session_id"] == str(session.session_id) + assert views._decode_session_cookie(token) is session