Skip to content

Commit 044d025

Browse files
luis5tbclaude
andcommitted
fix: eagerly validate DCR config at startup to prevent lazy init bypass
Move DCR service initialization from lazy (first-request) to eager (lifespan startup) so Cloud Run fails to start with missing/invalid DCR_ENCRYPTION_KEY instead of appearing healthy and failing on first DCR request. Add test coverage for encryption key error paths. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b0b0f31 commit 044d025

2 files changed

Lines changed: 46 additions & 0 deletions

File tree

src/lightspeed_agent/marketplace/app.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,19 @@ async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
3737
logger.error("Failed to initialize database: %s", e)
3838
raise
3939

40+
# Startup: Validate DCR configuration (fail-fast on Cloud Run)
41+
# This ensures DCR_ENCRYPTION_KEY is valid BEFORE the service becomes ready,
42+
# preventing silent failures when the first DCR request arrives.
43+
try:
44+
from lightspeed_agent.dcr import get_dcr_service
45+
46+
logger.info("Validating DCR service configuration")
47+
get_dcr_service() # Triggers DCRService.__init__() validation
48+
logger.info("DCR service initialized successfully")
49+
except Exception as e:
50+
logger.error("Failed to initialize DCR service: %s", e)
51+
raise
52+
4053
yield
4154

4255
# Shutdown: Close database connection

tests/test_dcr.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,39 @@ async def test_get_client(self, service):
277277
assert client.account_id == "valid-account-123"
278278

279279

280+
class TestDCRServiceEncryptionValidation:
281+
"""Tests for DCR service encryption key validation."""
282+
283+
def test_dcr_service_missing_key_on_cloud_run(self, monkeypatch, db_session):
284+
"""Test DCRService raises ValueError when DCR_ENCRYPTION_KEY is missing on Cloud Run."""
285+
from lightspeed_agent.config import get_settings
286+
287+
settings = get_settings()
288+
monkeypatch.setenv("K_SERVICE", "test-marketplace-handler")
289+
monkeypatch.setattr(settings, "dcr_encryption_key", "")
290+
291+
with pytest.raises(ValueError, match="DCR_ENCRYPTION_KEY is required in production"):
292+
DCRService()
293+
294+
def test_dcr_service_invalid_encryption_key(self, monkeypatch, db_session):
295+
"""Test that DCRService raises ValueError for invalid DCR_ENCRYPTION_KEY."""
296+
from lightspeed_agent.config import get_settings
297+
298+
settings = get_settings()
299+
monkeypatch.setattr(settings, "dcr_encryption_key", "not-a-valid-fernet-key")
300+
301+
with pytest.raises(ValueError, match="Invalid DCR_ENCRYPTION_KEY"):
302+
DCRService()
303+
304+
def test_encrypt_secret_without_key_raises(self, db_session):
305+
"""Test that _encrypt_secret raises RuntimeError when _fernet is None."""
306+
service = DCRService()
307+
service._fernet = None
308+
309+
with pytest.raises(RuntimeError, match="Cannot encrypt client secret"):
310+
service._encrypt_secret("test-secret")
311+
312+
280313
class TestDCRServiceDelete:
281314
"""Tests for DCR service client deletion."""
282315

0 commit comments

Comments
 (0)