Skip to content

feat: wire up CredentialService in onboarding API Keys screen#140

Merged
jbdevprimary merged 12 commits intomainfrom
claude/fix-pr135-feedback-gKQEA
Feb 16, 2026
Merged

feat: wire up CredentialService in onboarding API Keys screen#140
jbdevprimary merged 12 commits intomainfrom
claude/fix-pr135-feedback-gKQEA

Conversation

@jbdevprimary
Copy link
Contributor

Summary

Replaces #135 with all review feedback addressed.

Wires up CredentialService.validateCredential() and CredentialService.store() in the onboarding API Keys screen, replacing the previous TODO placeholders.

Review Feedback Addressed

  • Race condition protection (Amazon Q): Added AbortController pattern to cancel in-flight validation requests when user types rapidly
  • Error handling (Amazon Q + Gemini): Added try-catch blocks around all CredentialService calls with user-friendly error messages
  • Correct addCredential usage (Gemini): Uses setValidationResult() after addCredential() since addCredential defaults status to 'unknown'
  • Code deduplication (Gemini): Extracted storeCredential() helper, both providers stored via Promise.all
  • Type safety (Amazon Q + Gemini): Removed as any casts, using explicit 'anthropic' | 'openai' union type
  • Biome formatting (CI failure): Fixed waitFor callback and assertion formatting
  • Debounce timer cleanup (Amazon Q): Added cleanup on unmount for both timeout and abort refs

Changes

  • src/pages/onboarding/api-keys.tsx - Full CredentialService integration with error handling
  • src/pages/onboarding/components/APIKeyInput.tsx - Reusable API key input component
  • src/pages/onboarding/__tests__/api-keys.test.tsx - Comprehensive tests covering validation, storage, and error states

Test plan

  • Validates Anthropic key via CredentialService
  • Validates OpenAI key via CredentialService
  • Shows error state for invalid keys
  • Stores valid keys on continue with correct validation status
  • Disables continue button when no valid key exists
  • Skip navigates to create-project

Closes #135

https://claude.ai/code/session_01PQd4hGQQpmGTgpHc7kGjAE

google-labs-jules bot and others added 12 commits February 16, 2026 00:22
- Update `src/pages/onboarding/api-keys.tsx` to use `CredentialService` for validation and storage.
- Integrate `useCredentialStore` to update application state with valid credentials.
- Ensure keys are stored securely using hardware-backed encryption via `CredentialService.store`.
- Mask secrets before storing them in the Zustand state for UI display.

Co-authored-by: jbdevprimary <2650679+jbdevprimary@users.noreply.github.com>
- Sort imports in `src/pages/onboarding/api-keys.tsx` to satisfy Biome linting rules.
- Update `sonar-project.properties` to remove reference to non-existent `app` directory and point to valid sources (`src`, `packages`).

Co-authored-by: jbdevprimary <2650679+jbdevprimary@users.noreply.github.com>
- Fix `TS2353` error in `src/pages/onboarding/api-keys.tsx` by removing the `status` property from `addCredential` calls, as it is omitted from the action's input type.
- Restore `src/pages/onboarding/__tests__/api-keys.test.tsx` with updated expectations to match the type fix and ensure code coverage.

Co-authored-by: jbdevprimary <2650679+jbdevprimary@users.noreply.github.com>
- Fix Biome linting errors in `src/pages/onboarding/__tests__/api-keys.test.tsx` by sorting imports, using template literals instead of string concatenation, and replacing `as any` casts with `vi.mocked()` for better type safety.

Co-authored-by: jbdevprimary <2650679+jbdevprimary@users.noreply.github.com>
Co-authored-by: amazon-q-developer[bot] <208079219+amazon-q-developer[bot]@users.noreply.github.com>
Co-authored-by: amazon-q-developer[bot] <208079219+amazon-q-developer[bot]@users.noreply.github.com>
Co-authored-by: amazon-q-developer[bot] <208079219+amazon-q-developer[bot]@users.noreply.github.com>
Co-authored-by: amazon-q-developer[bot] <208079219+amazon-q-developer[bot]@users.noreply.github.com>
- Confirm fixes for Lint, Type Check, and SonarCloud failures.
- Ensure all test files comply with Biome rules.
- Validate `sonar-project.properties` configuration.

Co-authored-by: jbdevprimary <2650679+jbdevprimary@users.noreply.github.com>
- Extract `APIKeyInput` component to reduce complexity in `src/pages/onboarding/api-keys.tsx` and improve SonarCloud maintainability rating.
- Add comprehensive test cases in `src/pages/onboarding/__tests__/api-keys.test.tsx` covering "Skip" functionality, disabled states, and invalid inputs to meet coverage thresholds.

Co-authored-by: jbdevprimary <2650679+jbdevprimary@users.noreply.github.com>
- Implement robust error handling (try-catch) for all `CredentialService` operations.
- Add race condition protection using `AbortController` and debouncing for input validation.
- Fix `addCredential` usage by correctly chaining `setValidationResult` to set status.
- Refactor storage logic into `storeCredential` helper to reduce duplication.
- Remove unused imports in tests and ensure alignment with implementation.

Co-authored-by: jbdevprimary <2650679+jbdevprimary@users.noreply.github.com>
- Remove `as any` casts: use explicit `'anthropic' | 'openai'` type
  instead of unsafe `any` cast (Amazon Q + Gemini type safety feedback)
- Fix Biome formatting in test file: correct waitFor callback formatting
  and assertion line lengths to match Biome's expected format (CI failure)
- Race condition handling already in place via AbortController pattern
- Error handling already added with try-catch in validateKey/storeCredential
- setValidationResult correctly called after addCredential
- Code refactored into storeCredential helper with Promise.all

https://claude.ai/code/session_01PQd4hGQQpmGTgpHc7kGjAE
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 16, 2026

Warning

Rate limit exceeded

@jbdevprimary has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 1 minutes and 50 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

✨ Finishing touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch claude/fix-pr135-feedback-gKQEA

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@gemini-code-assist
Copy link

Summary of Changes

Hello @jbdevprimary, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the onboarding API Keys screen by integrating the CredentialService for real-time validation and secure storage of Anthropic and OpenAI API keys. It introduces robust error handling, debouncing with request cancellation to improve user experience during key input, and refactors the UI into a reusable component. These changes ensure that API keys are properly validated and stored, providing a more reliable and user-friendly onboarding process.

Highlights

  • Credential Service Integration: Fully wired up CredentialService.validateCredential() for real-time API key validation and CredentialService.store() for secure storage of Anthropic and OpenAI keys.
  • Robust Validation with Race Condition Protection: Implemented debounced key validation with AbortController to cancel in-flight requests, preventing race conditions and improving user experience during rapid typing.
  • Comprehensive Error Handling: Added try-catch blocks around all CredentialService calls, providing user-friendly error messages for validation and storage failures, including a global error display.
  • State Management Integration: Integrated useCredentialStore to correctly add new credentials and explicitly set their validation results to 'valid' after successful storage.
  • Code Refactoring and Reusability: Extracted a reusable APIKeyInput component to standardize the UI for API key input fields and created a storeCredential helper function to deduplicate storage logic.
  • Extensive Testing: Added a new, comprehensive test file covering various scenarios including key validation, error states, credential storage, and navigation flows for the API Keys page.
Changelog
  • src/pages/onboarding/tests/api-keys.test.tsx
    • Added new test file for ApiKeysPage.
    • Implemented tests for key validation, error states, and credential storage.
    • Mocked external services like CredentialService and useCredentialStore.
  • src/pages/onboarding/api-keys.tsx
    • Integrated CredentialService for key validation and storage.
    • Implemented debounce and AbortController for validation requests.
    • Added useCredentialStore hooks for adding and updating credential status.
    • Refactored UI to use the new APIKeyInput component.
    • Introduced global error handling for credential storage.
    • Removed old simulated validation logic and Spinner component.
  • src/pages/onboarding/components/APIKeyInput.tsx
    • Added new component for a reusable API key input field.
    • Encapsulated input, validation status indicators (spinner, success/close icons), and error/helper text.
    • Moved Spinner component definition here.
Activity
  • This pull request replaces a previous one (Wire up CredentialService in Onboarding API Keys screen #135), incorporating all prior review feedback.
  • Specific feedback addressed includes race condition protection, improved error handling, correct addCredential usage, code deduplication, type safety, Biome formatting fixes, and debounce timer cleanup.
  • The author has provided a detailed test plan and a link to a Claude AI session for further context.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@jbdevprimary jbdevprimary merged commit 372ba43 into main Feb 16, 2026
17 of 19 checks passed
@jbdevprimary jbdevprimary deleted the claude/fix-pr135-feedback-gKQEA branch February 16, 2026 00:25
Copy link
Contributor

@amazon-q-developer amazon-q-developer bot left a comment

Choose a reason for hiding this comment

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

This PR successfully implements CredentialService integration with proper error handling, race condition protection, and comprehensive test coverage. The implementation addresses all previous review feedback including AbortController patterns, try-catch blocks, cleanup on unmount, and code deduplication. No critical defects found that would block merge.


You can now have the agent implement changes and create commits directly on your pull request's source branch. Simply comment with /q followed by your request in natural language to ask the agent to make changes.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully wires up the CredentialService in the onboarding API keys screen, replacing previous placeholders. The changes are well-implemented, incorporating important features like debouncing with abort controllers to prevent race conditions, comprehensive error handling, and cleanup logic in useEffect. The code is also well-structured, with the creation of a reusable APIKeyInput component and a thorough new test suite. My feedback focuses on a couple of areas to further improve the code: enhancing the robustness of the tests by using more specific mock data, and increasing type safety in a helper function to align with the existing good practice of avoiding unnecessary type casting. Overall, this is a high-quality contribution.

});

// Mock useCredentialStore
const mockAddCredential = vi.fn(() => 'test-cred-id');

Choose a reason for hiding this comment

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

medium

The current mock for addCredential returns a static ID 'test-cred-id'. This can lead to less specific tests, especially when multiple credentials are added, as you can't distinguish between them. To make the test more robust and accurately reflect the behavior of adding multiple unique credentials, consider making the returned ID unique for each provider.

Suggested change
const mockAddCredential = vi.fn(() => 'test-cred-id');
const mockAddCredential = vi.fn((cred) => `test-cred-id-${cred.provider}`);

Comment on lines +160 to +163
expect(mockSetValidationResult).toHaveBeenCalledWith(
'test-cred-id',
expect.objectContaining({ isValid: true }),
);

Choose a reason for hiding this comment

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

medium

Following the suggestion to make mockAddCredential return unique IDs, this assertion can be strengthened to verify that setValidationResult is called correctly for each of the stored credentials. This ensures both keys are processed as expected. It's also good practice to assert the number of times the mock was called.

      expect(mockSetValidationResult).toHaveBeenCalledTimes(2);
      expect(mockSetValidationResult).toHaveBeenCalledWith(
        'test-cred-id-anthropic',
        expect.objectContaining({ isValid: true }),
      );
      expect(mockSetValidationResult).toHaveBeenCalledWith(
        'test-cred-id-openai',
        expect.objectContaining({ isValid: true }),
      );

Comment on lines +137 to +164
provider: CredentialProvider,
keyState: APIKeyState,
name: string,
secureStoreKey: string,
) => {
if (keyState.isValid && keyState.key) {
try {
// Cast provider to the store/mask API type ('anthropic' | 'openai')
const apiProvider = provider as 'anthropic' | 'openai';
await CredentialService.store(apiProvider, keyState.key);

const credId = addCredential({
provider,
name,
secureStoreKey,
maskedValue: CredentialService.maskSecret(keyState.key, apiProvider),
});

// Explicitly set validation result as valid since we just stored it
setValidationResult(credId, {
isValid: true,
expiresAt: undefined,
});
} catch (error) {
console.error(`Failed to store ${provider} credential:`, error);
throw new Error(`Failed to save ${name} key`);
}
}

Choose a reason for hiding this comment

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

medium

The storeCredential function can be made more type-safe. By narrowing the provider type in the signature to 'anthropic' | 'openai', you can eliminate the need for the type cast to apiProvider and use provider directly throughout the function. This improves readability and type safety.

    provider: 'anthropic' | 'openai',
    keyState: APIKeyState,
    name: string,
    secureStoreKey: string,
  ) => {
    if (keyState.isValid && keyState.key) {
      try {
        await CredentialService.store(provider, keyState.key);

        const credId = addCredential({
          provider,
          name,
          secureStoreKey,
          maskedValue: CredentialService.maskSecret(keyState.key, provider),
        });

        // Explicitly set validation result as valid since we just stored it
        setValidationResult(credId, {
          isValid: true,
          expiresAt: undefined,
        });
      } catch (error) {
        console.error(`Failed to store ${provider} credential:`, error);
        throw new Error(`Failed to save ${name} key`);
      }
    }

@sonarqubecloud
Copy link

jbdevprimary added a commit that referenced this pull request Feb 16, 2026
- Acknowledge that this PR is superseded by #140.
- No further code changes required here.

Co-authored-by: jbdevprimary <2650679+jbdevprimary@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants