Skip to content

Commit 703c996

Browse files
authored
Merge pull request #14 from luis5tb/jwt-validation-cloudrun
feat: block SKIP_JWT_VALIDATION in Cloud Run environments
2 parents 3f9060c + 0d60a51 commit 703c996

4 files changed

Lines changed: 75 additions & 1 deletion

File tree

deploy/cloudrun/marketplace-handler.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ spec:
7272
# Red Hat SSO Configuration
7373
- name: RED_HAT_SSO_ISSUER
7474
value: "https://sso.redhat.com/auth/realms/redhat-external"
75+
# Ensure production environment do not skip JWT validation
76+
- name: SKIP_JWT_VALIDATION
77+
value: "false"
7578
# DCR Configuration
7679
- name: DCR_ENABLED
7780
value: "true"

deploy/cloudrun/service.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,9 @@ spec:
8888
value: ""
8989
# Replace with the required scopes if any is needed
9090
# value: "agent:insights"
91+
# Ensure production environment do not skip JWT validation
92+
- name: SKIP_JWT_VALIDATION
93+
value: "false"
9194
# MCP Configuration
9295
# The agent connects to the MCP sidecar container over HTTP
9396
- name: MCP_TRANSPORT_MODE

src/lightspeed_agent/config/settings.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
"""Application settings and configuration management."""
22

3+
import os
34
from functools import lru_cache
45
from typing import Literal
56

6-
from pydantic import Field
7+
from pydantic import Field, model_validator
78
from pydantic_settings import BaseSettings, SettingsConfigDict
89

910

@@ -241,6 +242,21 @@ def keycloak_dcr_endpoint(self) -> str:
241242
description="Skip JWT validation (development only)",
242243
)
243244

245+
@model_validator(mode="after")
246+
def _block_skip_jwt_in_production(self) -> "Settings":
247+
"""Prevent SKIP_JWT_VALIDATION from being enabled in production.
248+
249+
Cloud Run sets K_SERVICE automatically. If that variable is present,
250+
this is a managed deployment and JWT validation must never be skipped.
251+
"""
252+
if self.skip_jwt_validation and os.getenv("K_SERVICE"):
253+
raise ValueError(
254+
"SKIP_JWT_VALIDATION=true is not allowed in Cloud Run "
255+
f"(K_SERVICE={os.getenv('K_SERVICE')}). "
256+
"This setting is intended for local development only."
257+
)
258+
return self
259+
244260
# OpenTelemetry Configuration
245261
otel_enabled: bool = Field(
246262
default=False,

tests/test_settings.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
"""Tests for application settings guards."""
2+
3+
import os
4+
from unittest.mock import patch
5+
6+
import pytest
7+
from pydantic import ValidationError
8+
9+
from lightspeed_agent.config import Settings
10+
11+
12+
class TestSkipJwtProductionGuard:
13+
"""Verify SKIP_JWT_VALIDATION cannot be enabled in Cloud Run."""
14+
15+
def _env_without_k_service(self) -> dict[str, str]:
16+
"""Return a copy of os.environ without K_SERVICE."""
17+
return {k: v for k, v in os.environ.items() if k != "K_SERVICE"}
18+
19+
def test_skip_jwt_allowed_without_k_service(self):
20+
"""SKIP_JWT_VALIDATION=true is fine when K_SERVICE is unset."""
21+
with patch.dict(os.environ, self._env_without_k_service(), clear=True):
22+
settings = Settings(skip_jwt_validation=True)
23+
assert settings.skip_jwt_validation is True
24+
25+
def test_skip_jwt_blocked_in_cloud_run(self):
26+
"""SKIP_JWT_VALIDATION=true must fail when K_SERVICE is set."""
27+
with patch.dict(
28+
os.environ, {"K_SERVICE": "lightspeed-agent"}, clear=False
29+
):
30+
with pytest.raises(
31+
ValidationError, match="not allowed in Cloud Run"
32+
):
33+
Settings(skip_jwt_validation=True)
34+
35+
def test_no_skip_jwt_allowed_in_cloud_run(self):
36+
"""SKIP_JWT_VALIDATION=false (default) is fine in Cloud Run."""
37+
with patch.dict(
38+
os.environ, {"K_SERVICE": "lightspeed-agent"}, clear=False
39+
):
40+
settings = Settings(skip_jwt_validation=False)
41+
assert settings.skip_jwt_validation is False
42+
43+
def test_skip_jwt_defaults_to_false(self):
44+
"""Default value of skip_jwt_validation is False."""
45+
with patch.dict(
46+
os.environ,
47+
self._env_without_k_service()
48+
| {"SKIP_JWT_VALIDATION": "false"},
49+
clear=True,
50+
):
51+
settings = Settings(skip_jwt_validation=False)
52+
assert settings.skip_jwt_validation is False

0 commit comments

Comments
 (0)