Problem
The test suite fails on contributor forks with:
openai.OpenAIError: Missing credentials. Please pass an api_key or set the OPENAI_API_KEY environment variable.
This happens on every test run — even tests that have nothing to do with the LLM — because LLMClient() is instantiated at module load time in finbot/core/llm/client.py:70:
llm_client = LLMClient() # runs at import, not on first use
When any test imports finbot.main, it triggers the full chain:
badges.py → ctf.evaluators → detectors.__init__ → indirect_exfil.py → LLMClient() → crash.
The CI workflow intentionally does not require an OpenAI key — the tests being run (vendor isolation, session management, user isolation, redis streams) have no LLM dependency. The module-level instantiation introduced in b180679 broke contributor CI silently.
Root Cause
b180679 added indirect_exfil.py, which imports LLMJudge at the top level. This triggers eager LLMClient() construction, which defaults to the openai provider and raises immediately without a key.
Fix
Set LLM_PROVIDER=mock at the job level in .github/workflows/test.yml. The mock provider is already implemented and skips all credential checks.
jobs:
test:
runs-on: ubuntu-latest
env:
LLM_PROVIDER: mock
A longer-term fix would be to lazy-initialize llm_client in client.py so it only constructs on first call, not on import.
Problem
The test suite fails on contributor forks with:
openai.OpenAIError: Missing credentials. Please pass an api_key or set the OPENAI_API_KEY environment variable.
This happens on every test run — even tests that have nothing to do with the LLM — because LLMClient() is instantiated at module load time in finbot/core/llm/client.py:70:
The CI workflow intentionally does not require an OpenAI key — the tests being run (vendor isolation, session management, user isolation, redis streams) have no LLM dependency. The module-level instantiation introduced in b180679 broke contributor CI silently.
Root Cause
b180679 added indirect_exfil.py, which imports LLMJudge at the top level. This triggers eager LLMClient() construction, which defaults to the openai provider and raises immediately without a key.
Fix
Set LLM_PROVIDER=mock at the job level in .github/workflows/test.yml. The mock provider is already implemented and skips all credential checks.
jobs:
test:
runs-on: ubuntu-latest
env:
LLM_PROVIDER: mock
A longer-term fix would be to lazy-initialize llm_client in client.py so it only constructs on first call, not on import.