From b15171594b5b67044748bd944160800b4cb635f8 Mon Sep 17 00:00:00 2001 From: Amar K P Date: Thu, 1 Oct 2026 20:34:53 +0530 Subject: [PATCH 1/2] test(demo): require explicit API keys or offline flag in demo runner --- tests/integration/test_demo.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/integration/test_demo.py b/tests/integration/test_demo.py index 74e9abb..00d7fc6 100644 --- a/tests/integration/test_demo.py +++ b/tests/integration/test_demo.py @@ -139,3 +139,28 @@ async def test_demo_script_runner() -> None: output = await demo_module.run_demo(offline=True) assert output is not None assert "3472" in output or "3,472" in output or "total" in output.lower() + + +def test_build_llm_strict_live_mode(monkeypatch: pytest.MonkeyPatch) -> None: + """Verify build_llm requires API keys when live provider is requested without --offline.""" + from examples.demo import build_llm + from agentkit.config import get_settings + + monkeypatch.setenv("GEMINI_API_KEY", "") + monkeypatch.setenv("OPENAI_API_KEY", "") + get_settings.cache_clear() + + # In live mode without key, it must raise ValueError + with pytest.raises(ValueError, match="API key for provider 'gemini' is missing"): + build_llm(offline=False, provider="gemini") + + with pytest.raises(ValueError, match="API key for provider 'openai' is missing"): + build_llm(offline=False, provider="openai") + + # In offline or fake mode, it returns FakeLLMClient + fake_client_offline = build_llm(offline=True, provider="gemini") + assert isinstance(fake_client_offline, FakeLLMClient) + + fake_client_fake_prov = build_llm(offline=False, provider="fake") + assert isinstance(fake_client_fake_prov, FakeLLMClient) + From 460d52fc1c87d34b95c31707436a55be05a56000 Mon Sep 17 00:00:00 2001 From: Amar K P Date: Thu, 1 Oct 2026 20:35:58 +0530 Subject: [PATCH 2/2] feat(demo): enforce explicit API keys in demo and clean up sample .env --- README.md | 9 +++------ examples/demo.py | 15 +++++++++++---- tests/integration/test_demo.py | 3 +-- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 1c49bc1..4934074 100644 --- a/README.md +++ b/README.md @@ -100,11 +100,9 @@ cp .env.example .env Edit `.env`: ```ini -ENVIRONMENT=development -LOG_LEVEL=INFO - # LLM Providers (at least one key or use offline mode) LLM_PROVIDER=gemini +LLM_MODEL=gemini-2.0-flash GEMINI_API_KEY=your_gemini_api_key_here OPENAI_API_KEY=your_openai_api_key_here @@ -112,9 +110,8 @@ OPENAI_API_KEY=your_openai_api_key_here DATABASE_URL=postgresql+asyncpg://agentkit:agentkit_password@localhost:5432/agentkit REDIS_URL=redis://localhost:6379/0 -# Security -API_KEYS=dev_key_1,dev_key_2 -JWT_SECRET=super_secret_jwt_key_at_least_32_bytes_long +# Security (comma-separated authorized keys) +API_KEYS=ak_test_key_12345,ak_admin_key_67890 ``` ### 4. Running with Docker Compose (Recommended) diff --git a/examples/demo.py b/examples/demo.py index ec57942..3d9e68b 100644 --- a/examples/demo.py +++ b/examples/demo.py @@ -144,17 +144,24 @@ def build_fake_llm() -> LLMClient: def build_llm(offline: bool, provider: str) -> LLMClient: - """Resolve the LLM client, degrading to the scripted fake when no key is present.""" + """Resolve the LLM client, requiring valid API keys unless running in offline/fake mode.""" if offline or provider == "fake": return build_fake_llm() settings = get_settings() key_present = settings.GEMINI_API_KEY if provider == "gemini" else settings.OPENAI_API_KEY if not key_present: - logger.warning("No API key for provider '%s'; falling back to FakeLLMClient.", provider) - return build_fake_llm() + key_name = "GEMINI_API_KEY" if provider == "gemini" else "OPENAI_API_KEY" + raise ValueError( + f"API key for provider '{provider}' is missing ({key_name} is not set). " + f"To run offline without real API credentials, pass --offline or --provider fake." + ) - return create_llm_client(provider) + return create_llm_client( + provider=provider, + api_key=key_present, + model=settings.LLM_MODEL, + ) async def run_demo( diff --git a/tests/integration/test_demo.py b/tests/integration/test_demo.py index 00d7fc6..e75b8a3 100644 --- a/tests/integration/test_demo.py +++ b/tests/integration/test_demo.py @@ -143,8 +143,8 @@ async def test_demo_script_runner() -> None: def test_build_llm_strict_live_mode(monkeypatch: pytest.MonkeyPatch) -> None: """Verify build_llm requires API keys when live provider is requested without --offline.""" - from examples.demo import build_llm from agentkit.config import get_settings + from examples.demo import build_llm monkeypatch.setenv("GEMINI_API_KEY", "") monkeypatch.setenv("OPENAI_API_KEY", "") @@ -163,4 +163,3 @@ def test_build_llm_strict_live_mode(monkeypatch: pytest.MonkeyPatch) -> None: fake_client_fake_prov = build_llm(offline=False, provider="fake") assert isinstance(fake_client_fake_prov, FakeLLMClient) -