-
Notifications
You must be signed in to change notification settings - Fork 223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
OPIK-547 Store and retrieve LLM provider api key #845
OPIK-547 Store and retrieve LLM provider api key #845
Conversation
b2bbb65
to
c46f4ef
Compare
apps/opik-backend/src/main/java/com/comet/opik/api/ProviderApiKeyUpdate.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/infrastructure/OpikConfiguration.java
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/infrastructure/EncryptionService.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/infrastructure/EncryptionService.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/infrastructure/EncryptionConfig.java
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/domain/ProxyService.java
Outdated
Show resolved
Hide resolved
log.info("Got provider api key with id '{}', workspaceId '{}'", id, workspaceId); | ||
|
||
return providerApiKey.toBuilder() | ||
.apiKey(encryptionService.decrypt(providerApiKey.apiKey())) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is for internal usage. Api key will not be serialized, and should never be exposed outside of application. So there is no sense in additional Serializer configurations.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Related to the other thread. Ideally, api key deserialization should be triggered on the last minute, just right before inserting it as auth header in the client call towards the provider.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This field is excluded from serialization when returned to UI as I mentioned above. I removed decryption, since it will be used in some other service which is not implemented yet.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's polish this a bit more and it should be good to go.
Most of comments are minor, we can discuss the biggest ones:
- Early encryption, late decryption.
- Listing endpoint: fine to be in a separated PR.
apps/opik-backend/src/main/java/com/comet/opik/api/ProviderApiKey.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ProxyResource.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ProxyResource.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/api/resources/v1/priv/ProxyResource.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/domain/ProviderApiKeyDAO.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/infrastructure/EncryptionService.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/infrastructure/EncryptionService.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/infrastructure/EncryptionService.java
Outdated
Show resolved
Hide resolved
apps/opik-backend/src/main/java/com/comet/opik/infrastructure/EncryptionService.java
Outdated
Show resolved
Hide resolved
...d/src/main/resources/liquibase/db-app-state/migrations/000006_add_provider_api_key_table.sql
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few more comments, but feel free to address them in a following PR
@@ -69,7 +70,7 @@ public void initialize(Bootstrap<OpikConfiguration> bootstrap) { | |||
.withPlugins(new SqlObjectPlugin(), new Jackson2Plugin())) | |||
.modules(new DatabaseAnalyticsModule(), new IdGeneratorModule(), new AuthModule(), new RedisModule(), | |||
new RateLimitModule(), new NameGeneratorModule(), new HttpModule(), new EventModule(), | |||
new ConfigurationModule(), new BiModule()) | |||
new ConfigurationModule(), new BiModule(), new EncryptionUtilsModule()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't need a module since this will be static. We can just set the configuration using the run
method below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it could be set in run. Since we are using DI this approach seems more consistent. Can be changed, don't have any preferences here.
|
||
@Override | ||
public ProviderApiKey get(UUID id, String workspaceId) { | ||
log.info("Getting provider api key with id '{}', workspaceId '{}'", id, workspaceId); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's be consistent with logs. We can use them either in all public methods or just as controllers.
} | ||
|
||
public static String encrypt(String data) { | ||
init(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We can init this only once when setting the config
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree, will make code more readable.
updateProviderApiKey(UUID.randomUUID(), providerApiKey, apiKey, workspaceName, 404); | ||
} | ||
|
||
private UUID createProviderApiKey(LlmProvider provider, String providerApiKey, String apiKey, String workspaceName, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should use Podam to generate the beans. Also, we can extract these cans to a ResourceClient class like SpanResourceClient,
for reusability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree about reusability. Regarding Podam, LlmProvider
can be generated within the method, but providerApiKey
should be passed as param, since it's used lated in the outer scope.
Details
Store and retrieve LLM provider api key
Testing
Added integration tests
Documentation
https://www.notion.so/cometml/Online-Scoring-HLD-14d7124010a380508f32fdbd541e5705