Skip to content

Conversation

@AkhileshNegi
Copy link
Collaborator

@AkhileshNegi AkhileshNegi commented May 12, 2025

Summary

Target issue is #149

Checklist

Before submitting a pull request, please ensure that you mark these task.

  • Ran fastapi run --reload app/main.py or docker compose up in the repository root and test.
  • If you've fixed a bug or added code that is tested and has test cases.

Notes

  • Encrypting the credentials column
  • Adding support for adding multiple credentials per organization, per project and per provider
  • Added testcases

priyanshu6238 and others added 13 commits May 10, 2025 11:21
…pecific credentials

- Introduced a new column 'provider' in the credential table to support multiple credential providers.
- Updated API routes to handle provider-specific credential operations, including creation, retrieval, updating, and deletion.
- Enhanced validation for provider credentials and added support for multiple providers in the data model.
- Refactored existing credential handling functions to accommodate the new structure and improve error handling.
- Ensured backward compatibility by maintaining existing functionality while expanding capabilities.
…reation, enhance readability, and ensure proper handling of provider-specific data.
…roper checks for credential existence; update tests for accuracy in response validation.
… and improved error responses; update tests for accurate status codes and messages.
…redential fields; improve error responses for organization checks and unexpected exceptions.
@codecov
Copy link

codecov bot commented May 12, 2025

Codecov Report

Attention: Patch coverage is 90.23355% with 46 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
backend/app/crud/credentials.py 79.74% 16 Missing ⚠️
backend/app/api/routes/credentials.py 77.41% 14 Missing ⚠️
backend/app/api/routes/threads.py 15.38% 11 Missing ⚠️
backend/app/core/security.py 80.00% 4 Missing ⚠️
backend/app/core/providers.py 95.83% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

This was linked to issues May 12, 2025
@AkhileshNegi AkhileshNegi self-assigned this May 12, 2025
@AkhileshNegi AkhileshNegi added the enhancement New feature or request label May 12, 2025
Copy link
Contributor

@jerome-white jerome-white left a comment

Choose a reason for hiding this comment

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

The most significant issues I see are management of exceptions: raises inside try-except blocks. Consider refactoring. If that is too much trouble, "resolve" my comments manually and move on

if "Unsupported provider" in str(e):
raise HTTPException(status_code=400, detail=str(e))
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
Copy link
Contributor

Choose a reason for hiding this comment

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

Because of these outer exception handlers, and most notably because of the base exception handling here, none of the exceptions in the function body will be raised on their own. Notably, all HTTPExceptions raised in the function body will be cause by this parent exception, which will return 500 to the user. Because the body-exceptions raise different status codes, I imagine this -- raising 500 always -- was not the intention.

if not creds:
raise HTTPException(status_code=404, detail="Credentials not found")
return APIResponse.success_response([cred.to_public() for cred in creds])
except HTTPException:
Copy link
Contributor

Choose a reason for hiding this comment

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

Consider restructuring the code so that this doesn't have to be re-raised. get_creds_by_org is probably the only call within this function that needs to be a in a try-except block

Comment on lines 117 to 121
if provider_creds is None:
raise HTTPException(
status_code=404, detail="Provider credentials not found"
)
return APIResponse.success_response(provider_creds)
Copy link
Contributor

Choose a reason for hiding this comment

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

Do these lines need to be in the try-except block? If not, it would alleviate the need for the HTTPException to be caught (a few lines down)

Comment on lines +141 to +144
if not creds_in or not creds_in.provider or not creds_in.credential:
raise HTTPException(
status_code=400, detail="Provider and credential must be provided"
)
Copy link
Contributor

Choose a reason for hiding this comment

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

Does this need to be in a try-except?


def to_public(self) -> "CredsPublic":
"""Convert the database model to a public model with decrypted credentials."""
from app.core.security import decrypt_credentials
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason for importing within the method? (Instead of in the global scope?) It's fine if the global scope leads to import cycles; but inside the function means the import will be called every time the function is, which won't break the code, but will have performance implications

try:
return Provider(provider.lower())
except ValueError:
supported = ", ".join([p.value for p in Provider])
Copy link
Contributor

Choose a reason for hiding this comment

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

Remove the brackets to prevent Python from instantiating the list:

supported = ", ".join(p.value for p in Provider)


def get_supported_providers() -> List[str]:
"""Return a list of all supported provider names."""
return [p.value for p in Provider]
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you really need to return the list, or would a generator do the trick?

yield from (p.value for p in Provider)

If most callers iterate the list, or try to find something in it, a generator would be more efficient

Example: {"openai": {"api_key": "..."}, "gemini": {"api_key": "..."}}
"""

credential: Dict[str, Any] = Field(
Copy link
Collaborator

Choose a reason for hiding this comment

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

so then we take the provider and credentials together as key value pair, and then later gets dissected into two separate column? Why could we not take provider name separately and the credentials separately.

Copy link
Contributor

Choose a reason for hiding this comment

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

Because that way, we would be restricting the behavior of data insertion by the user.

@AkhileshNegi AkhileshNegi force-pushed the feature/add-provider-org-credentials branch from 44fd11b to e2d20fa Compare May 13, 2025 16:55
@AkhileshNegi AkhileshNegi merged commit fe4e92f into main May 14, 2025
1 check passed
@AkhileshNegi AkhileshNegi deleted the feature/add-provider-org-credentials branch May 14, 2025 07:57
@AkhileshNegi AkhileshNegi linked an issue Jun 5, 2025 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Credentials : Use this functionality in threads endpoint Credentials: Custom Provider Input OpenAI: Add keys

5 participants