Skip to content
This repository was archived by the owner on Jul 6, 2026. It is now read-only.

🔒 Remove hardcoded OpenAI API key fallback - #22

Closed
ereezyy wants to merge 1 commit into
mainfrom
fix-hardcoded-api-key-10333503756924995807
Closed

🔒 Remove hardcoded OpenAI API key fallback#22
ereezyy wants to merge 1 commit into
mainfrom
fix-hardcoded-api-key-10333503756924995807

Conversation

@ereezyy

@ereezyy ereezyy commented Mar 9, 2026

Copy link
Copy Markdown
Owner

🎯 What: The hardcoded 'demo-key' fallback string in src/services/aiService.ts was being used when VITE_OPENAI_API_KEY was not provided.

⚠️ Risk: Hardcoded credentials (CWE-798) can lead to unauthorized access if the key is valid, or misleading application states if it's a dummy value. It bypasses proper environment configuration.

🛡️ Solution:

  • Removed the 'demo-key' string from the codebase.
  • Implemented explicit validation in callAIProvider to throw an Error if apiKey is missing for OpenAI or Hugging Face.
  • This error correctly triggers the existing fallback provider logic in AIService.initialize().
  • Added src/services/aiService.test.ts to ensure that initialization correctly fails or falls back when keys are missing, and that validation logic works as expected.

PR created automatically by Jules for task 10333503756924995807 started by @ereezyy

Summary by Sourcery

Enforce explicit API key validation for AI providers and remove the insecure hardcoded OpenAI API key fallback.

Bug Fixes:

  • Reject OpenAI and Hugging Face calls when the corresponding API key is missing instead of silently proceeding with a hardcoded fallback key.

Enhancements:

  • Validate provider configuration by throwing explicit errors when OpenAI or Hugging Face API keys are absent, allowing existing fallback provider logic to engage correctly.

Tests:

  • Add unit tests for AIService initialization and provider selection to cover missing-key scenarios and validation behavior.

Summary by CodeRabbit

  • Bug Fixes

    • Enhanced API key validation for OpenAI and Hugging Face providers with descriptive error messages when keys are missing or invalid.
    • Removed the default fallback key for OpenAI provider; the service now requires explicit API key configuration.
  • Tests

    • Added comprehensive unit tests for AI service covering initialization failures, fallback provider scenarios, and error handling when API keys are missing.

- Removed hardcoded 'demo-key' from AIService initialization.
- Added runtime validation to throw errors when required API keys are missing.
- Added unit tests to verify fallback logic and key validation.
@google-labs-jules

Copy link
Copy Markdown

👋 Jules, reporting for duty! I'm here to lend a hand with this pull request.

When you start a review, I'll add a 👀 emoji to each comment to let you know I've read it. I'll focus on feedback directed at me and will do my best to stay out of conversations between you and other bots or reviewers to keep the noise down.

I'll push a commit with your requested changes shortly after. Please note there might be a delay between these steps, but rest assured I'm on the job!

For more direct control, you can switch me to Reactive Mode. When this mode is on, I will only act on comments where you specifically mention me with @jules. You can find this option in the Pull Request section of your global Jules UI settings. You can always switch back!

New to Jules? Learn more at jules.google/docs.


For security, I will only act on instructions from the user who triggered this task.

@sourcery-ai

sourcery-ai Bot commented Mar 9, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Removes the hardcoded OpenAI API key fallback and adds stricter runtime validation plus tests to ensure correct failure and fallback behavior when API keys are missing.

Sequence diagram for AIService provider call with API key validation and fallback

sequenceDiagram
  actor Client
  participant AIService
  participant Provider as PrimaryProvider
  participant Fallback as FallbackProvider

  Client->>AIService: initialize()
  activate AIService
  AIService->>Provider: callAIProvider(prompt, type, primaryConfig)
  activate Provider
  Provider-->>Provider: validate apiKey
  alt Missing apiKey for OpenAI
    Provider-->>AIService: throw Error(OpenAI API key is missing)
  else Missing apiKey for HuggingFace
    Provider-->>AIService: throw Error(Hugging Face API key is missing)
  else Valid apiKey
    Provider-->>AIService: providerResponse
  end
  deactivate Provider

  alt Error thrown due to missing apiKey
    AIService-->>AIService: catch Error
    AIService->>Fallback: callAIProvider(prompt, type, fallbackConfig)
    activate Fallback
    Fallback-->>AIService: fallbackResponse
    deactivate Fallback
    AIService-->>Client: fallbackResponse
  else No error
    AIService-->>Client: providerResponse
  end
  deactivate AIService
Loading

Updated class diagram for AIService provider configuration and key validation

classDiagram
  class AIServiceConfig {
    <<interface>>
    +string provider
    +string apiKey
    +string modelEndpoint
    +string localModel
  }

  class AIService {
    -AIServiceConfig primaryConfig
    -AIServiceConfig[] fallbackConfigs
    +AIService(primaryConfig AIServiceConfig, fallbackConfigs AIServiceConfig[])
    +initialize() Promise~void~
    +callAIProvider(prompt string, type string, config AIServiceConfig) Promise~string~
    -callOpenAI(prompt string, type string, apiKey string) Promise~string~
    -callHuggingFace(prompt string, apiKey string, modelEndpoint string) Promise~string~
    -callOllama(prompt string, localModel string) Promise~string~
  }

  AIService o-- AIServiceConfig

  class ExampleInitialization {
    +createAIService() AIService
  }

  ExampleInitialization ..> AIService : uses

  class Environment {
    +string VITE_OPENAI_API_KEY
  }

  ExampleInitialization ..> Environment : reads

  note for AIServiceConfig "For providers openai and huggingface, apiKey must be present; missing keys cause callAIProvider to throw an Error, triggering fallback logic in AIService.initialize."
Loading

File-Level Changes

Change Details Files
Add explicit API key validation per provider when calling remote AI backends.
  • Update OpenAI branch in callAIProvider to throw a descriptive error if config.apiKey is missing before calling callOpenAI.
  • Update Hugging Face branch in callAIProvider to throw a descriptive error if config.apiKey is missing before calling callHuggingFace, while still requiring modelEndpoint.
src/services/aiService.ts
Remove the hardcoded demo OpenAI API key and rely solely on environment configuration.
  • Change AIService default configuration to use import.meta.env.VITE_OPENAI_API_KEY directly without a 'demo-key' fallback.
src/services/aiService.ts
Introduce tests covering initialization and validation behavior when API keys are missing.
  • Add a new test suite for AIService that asserts initialization fails or falls back correctly when OpenAI/Hugging Face API keys are missing.
  • Test that the new validation logic throws appropriate errors for missing API keys, aligning with existing fallback provider behavior in AIService.initialize().
src/services/aiService.test.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Mar 9, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Added comprehensive unit tests for AIService covering initialization failures and error handling when API keys are missing. Updated AIService implementation to validate API keys at runtime for OpenAI and Hugging Face providers before use, and removed the default demo-key fallback for OpenAI.

Changes

Cohort / File(s) Summary
AIService Implementation
src/services/aiService.ts
Added runtime validation to verify OpenAI and Hugging Face API keys exist before use; removed non-null assertions and default 'demo-key' fallback for OpenAI.
AIService Tests
src/services/aiService.test.ts
Added unit tests covering initialization failures when primary key is missing without fallbacks, fallback provider handling (ollama), and error scenarios for missing OpenAI and Hugging Face keys.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Poem

🐰✨ With keys now checked before we call,
No more demo-keys to fall,
Tests ensure our errors ring,
Validation's quite the careful thing! 🔑

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Remove hardcoded OpenAI API key fallback' accurately and clearly summarizes the main change in the pull request - removing the hardcoded 'demo-key' fallback from AIService.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix-hardcoded-api-key-10333503756924995807

Comment @coderabbitai help to get the list of available commands and usage tips.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've left some high level feedback:

  • Since you're now explicitly validating apiKey for OpenAI and Hugging Face, consider adding similar runtime checks (with clear error messages) for other required fields like config.modelEndpoint and config.localModel instead of relying on non-null assertions.
  • The new Error messages are quite generic; you might make them more actionable (e.g., hinting at which env var is missing) to simplify debugging misconfigurations in different environments.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Since you're now explicitly validating `apiKey` for OpenAI and Hugging Face, consider adding similar runtime checks (with clear error messages) for other required fields like `config.modelEndpoint` and `config.localModel` instead of relying on non-null assertions.
- The new `Error` messages are quite generic; you might make them more actionable (e.g., hinting at which env var is missing) to simplify debugging misconfigurations in different environments.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, you can upgrade your account or add credits to your account and enable them for code reviews in your settings.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/services/aiService.test.ts`:
- Around line 49-50: Replace the two TypeScript suppression comments in the
aiService tests: change the `// `@ts-ignore`` directives used before the private
method access calls to `// `@ts-expect-error`` (the tests that call the private
method via `service.callAIProvider('test', 'test')` and the other suppression
around line 59); this will satisfy the `@typescript-eslint/ban-ts-comment` rule
and ensure the suppression fails if the underlying type error is resolved.

In `@src/services/aiService.ts`:
- Around line 196-200: The Hugging Face branch in AIService uses
config.modelEndpoint! without validating it; update the 'huggingface' case in
the method that dispatches to callHuggingFace to check that config.modelEndpoint
is present (non-empty string) and throw a clear Error like "Hugging Face
modelEndpoint is missing" if not, then call this.callHuggingFace(prompt,
config.apiKey, config.modelEndpoint) without the non-null assertion; reference
the 'huggingface' case, 'config.modelEndpoint', and 'callHuggingFace' when
making the change.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 376b080d-665f-4411-8a44-30756867a71f

📥 Commits

Reviewing files that changed from the base of the PR and between 2917319 and 4c21f65.

📒 Files selected for processing (2)
  • src/services/aiService.test.ts
  • src/services/aiService.ts

Comment on lines +49 to +50
// @ts-ignore - accessing private method for testing
await expect(service.callAIProvider('test', 'test')).rejects.toThrow('OpenAI API key is missing');

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check if the test file exists and read the relevant lines
if [ -f "src/services/aiService.test.ts" ]; then
  echo "=== File found, reading context around lines 49-50 and 59-60 ==="
  sed -n '45,65p' "src/services/aiService.test.ts"
else
  echo "File not found. Searching for it..."
  find . -name "aiService.test.ts" -type f
fi

Repository: ereezyy/Sol_Horse

Length of output: 840


🏁 Script executed:

# Check for ESLint configuration files
echo "=== Checking for ESLint config ==="
ls -la | grep -E "eslint|\.eslintrc|eslint\.config"
if [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f ".eslintrc.yml" ]; then
  echo "=== ESLint configuration found ==="
  cat .eslintrc.* 2>/dev/null || echo "Config not readable"
fi

# Also check package.json for ESLint config
if [ -f "package.json" ]; then
  echo "=== Checking package.json for eslintConfig ==="
  jq '.eslintConfig // empty' package.json
fi

Repository: ereezyy/Sol_Horse

Length of output: 210


🏁 Script executed:

# Check for TypeScript config and ESLint rules
echo "=== TypeScript configuration ==="
if [ -f "tsconfig.json" ]; then
  head -50 tsconfig.json
fi

Repository: ereezyy/Sol_Horse

Length of output: 212


🏁 Script executed:

# Read the ESLint configuration
echo "=== ESLint Configuration ==="
cat eslint.config.js

Repository: ereezyy/Sol_Horse

Length of output: 828


🏁 Script executed:

# Also check the tsconfig.app.json which is likely the main one
echo "=== TypeScript App Configuration ==="
cat tsconfig.app.json

Repository: ereezyy/Sol_Horse

Length of output: 649


Replace @ts-ignore with @ts-expect-error on lines 49 and 59.

The ESLint @typescript-eslint/ban-ts-comment rule (enforced via tseslint.configs.recommended) allows only @ts-expect-error directives. @ts-ignore violates this rule and can silently become dead suppression if the underlying type error is fixed. @ts-expect-error is the correct directive for intentional type suppressions.

Proposed fix
-    // `@ts-ignore` - accessing private method for testing
+    // `@ts-expect-error` - accessing private method for testing
     await expect(service.callAIProvider('test', 'test')).rejects.toThrow('OpenAI API key is missing');
...
-    // `@ts-ignore` - accessing private method for testing
+    // `@ts-expect-error` - accessing private method for testing
     await expect(service.callAIProvider('test', 'test')).rejects.toThrow('Hugging Face API key is missing');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// @ts-ignore - accessing private method for testing
await expect(service.callAIProvider('test', 'test')).rejects.toThrow('OpenAI API key is missing');
// `@ts-expect-error` - accessing private method for testing
await expect(service.callAIProvider('test', 'test')).rejects.toThrow('OpenAI API key is missing');
🧰 Tools
🪛 ESLint

[error] 49-49: Use "@ts-expect-error" instead of "@ts-ignore", as "@ts-ignore" will do nothing if the following line is error-free.

(@typescript-eslint/ban-ts-comment)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/aiService.test.ts` around lines 49 - 50, Replace the two
TypeScript suppression comments in the aiService tests: change the `//
`@ts-ignore`` directives used before the private method access calls to `//
`@ts-expect-error`` (the tests that call the private method via
`service.callAIProvider('test', 'test')` and the other suppression around line
59); this will satisfy the `@typescript-eslint/ban-ts-comment` rule and ensure
the suppression fails if the underlying type error is resolved.

Comment thread src/services/aiService.ts
Comment on lines 196 to +200
case 'huggingface':
return await this.callHuggingFace(prompt, config.apiKey!, config.modelEndpoint!);
if (!config.apiKey) {
throw new Error('Hugging Face API key is missing');
}
return await this.callHuggingFace(prompt, config.apiKey, config.modelEndpoint!);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Validate modelEndpoint before invoking Hugging Face.

Line 200 still relies on config.modelEndpoint!. Because modelEndpoint is optional in AIServiceConfig, a Hugging Face config with an API key but no endpoint still makes it past the new guard and fails later as a generic fetch/runtime error instead of the explicit config error this PR is trying to enforce.

Proposed fix
       case 'huggingface':
         if (!config.apiKey) {
           throw new Error('Hugging Face API key is missing');
         }
-        return await this.callHuggingFace(prompt, config.apiKey, config.modelEndpoint!);
+        if (!config.modelEndpoint) {
+          throw new Error('Hugging Face model endpoint is missing');
+        }
+        return await this.callHuggingFace(prompt, config.apiKey, config.modelEndpoint);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
case 'huggingface':
return await this.callHuggingFace(prompt, config.apiKey!, config.modelEndpoint!);
if (!config.apiKey) {
throw new Error('Hugging Face API key is missing');
}
return await this.callHuggingFace(prompt, config.apiKey, config.modelEndpoint!);
case 'huggingface':
if (!config.apiKey) {
throw new Error('Hugging Face API key is missing');
}
if (!config.modelEndpoint) {
throw new Error('Hugging Face model endpoint is missing');
}
return await this.callHuggingFace(prompt, config.apiKey, config.modelEndpoint);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/services/aiService.ts` around lines 196 - 200, The Hugging Face branch in
AIService uses config.modelEndpoint! without validating it; update the
'huggingface' case in the method that dispatches to callHuggingFace to check
that config.modelEndpoint is present (non-empty string) and throw a clear Error
like "Hugging Face modelEndpoint is missing" if not, then call
this.callHuggingFace(prompt, config.apiKey, config.modelEndpoint) without the
non-null assertion; reference the 'huggingface' case, 'config.modelEndpoint',
and 'callHuggingFace' when making the change.

@ereezyy ereezyy closed this Jul 6, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant