fix: mask apiKey in OvhAiEmbeddingModel builder toString (#5608)
## Issue Closes #5607 ## Change `OvhAiEmbeddingModel.OvhAiEmbeddingModelBuilder.toString()` printed the API key in plain text via `", apiKey=" + this.apiKey`, so any log or exception that renders the builder leaked the OVHcloud key. It now masks the key, matching the merged sibling builders JinaEmbeddingModel (#3680), JinaScoringModel/JinaClient (#5539), and NomicEmbeddingModel (#5559): - `", apiKey=" + (this.apiKey == null ? null : "********")` A null key still renders as `apiKey=null` (no NPE); no other field is a secret. Added unit test `OvhAiEmbeddingModelTest` (JUnit 5 + AssertJ, no new dependencies), mirroring `JinaScoringModelBuilderTest` from #5539: - with a key set, `toString()` contains `apiKey=********` and not the raw value - with no key, `toString()` contains `apiKey=null` Note: unlike Jina (constructors only), the whole `OvhAiEmbeddingModel` class is `@Deprecated(forRemoval = true, since = "1.14.0")`. Masking is still worthwhile to stop leaking the key while the class is in use. The functional change is one line in `toString()`; the remaining file diff is Spotless reformatting a previously unformatted file (`ratchetFrom origin/main`), not manual edits. Module unit tests and `spotless:check` pass; the `*IT` needs an API key and was not run. ## General checklist - [X] There are no breaking changes (API, behaviour) - [X] I have added unit and/or integration tests for my change - [X] The tests cover both positive and negative cases - [X] I have manually run all the unit and integration tests in the module I have added/changed, and they are all green - [ ] I have manually run all the unit and integration tests in the core and main modules, and they are all green - [ ] I have added/updated the documentation - [ ] I have added an example in the examples repo (only for "big" features) - [ ] I have added/updated Spring Boot starter(s) (if applicable) <!-- "Checklist for adding new maven module" and both embedding-store checklists omitted: not applicable (this is a one-line fix to an existing module, no new module and no embedding-store integration change). -->
This commit is contained in:
parent
af67c71917
commit
166d202876
|
|
@ -1,5 +1,9 @@
|
|||
package dev.langchain4j.model.ovhai;
|
||||
|
||||
import static dev.langchain4j.internal.RetryUtils.withRetryMappingExceptions;
|
||||
import static dev.langchain4j.internal.Utils.getOrDefault;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
|
||||
import dev.langchain4j.data.embedding.Embedding;
|
||||
import dev.langchain4j.data.segment.TextSegment;
|
||||
import dev.langchain4j.model.embedding.EmbeddingModel;
|
||||
|
|
@ -7,14 +11,9 @@ import dev.langchain4j.model.output.Response;
|
|||
import dev.langchain4j.model.ovhai.internal.api.EmbeddingRequest;
|
||||
import dev.langchain4j.model.ovhai.internal.api.EmbeddingResponse;
|
||||
import dev.langchain4j.model.ovhai.internal.client.DefaultOvhAiClient;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.List;
|
||||
|
||||
import static dev.langchain4j.internal.RetryUtils.withRetryMappingExceptions;
|
||||
import static dev.langchain4j.internal.Utils.getOrDefault;
|
||||
import static java.util.stream.Collectors.toList;
|
||||
import org.slf4j.Logger;
|
||||
|
||||
/**
|
||||
* @deprecated use {@code OpenAiEmbeddingModel} from {@code langchain4j-open-ai} module instead
|
||||
|
|
@ -26,16 +25,14 @@ public class OvhAiEmbeddingModel implements EmbeddingModel {
|
|||
private final int maxRetries;
|
||||
|
||||
private OvhAiEmbeddingModel(OvhAiEmbeddingModelBuilder builder) {
|
||||
this.client =
|
||||
DefaultOvhAiClient
|
||||
.builder()
|
||||
.baseUrl(builder.baseUrl)
|
||||
.apiKey(builder.apiKey)
|
||||
.timeout(getOrDefault(builder.timeout, Duration.ofSeconds(60)))
|
||||
.logRequests(getOrDefault(builder.logRequests, false))
|
||||
.logResponses(getOrDefault(builder.logResponses, false))
|
||||
.logger(builder.logger)
|
||||
.build();
|
||||
this.client = DefaultOvhAiClient.builder()
|
||||
.baseUrl(builder.baseUrl)
|
||||
.apiKey(builder.apiKey)
|
||||
.timeout(getOrDefault(builder.timeout, Duration.ofSeconds(60)))
|
||||
.logRequests(getOrDefault(builder.logRequests, false))
|
||||
.logResponses(getOrDefault(builder.logResponses, false))
|
||||
.logger(builder.logger)
|
||||
.build();
|
||||
this.maxRetries = getOrDefault(builder.maxRetries, 2);
|
||||
}
|
||||
|
||||
|
|
@ -56,17 +53,14 @@ public class OvhAiEmbeddingModel implements EmbeddingModel {
|
|||
@Override
|
||||
public Response<List<Embedding>> embedAll(List<TextSegment> textSegments) {
|
||||
|
||||
EmbeddingRequest request = EmbeddingRequest
|
||||
.builder()
|
||||
EmbeddingRequest request = EmbeddingRequest.builder()
|
||||
.input(textSegments.stream().map(TextSegment::text).collect(toList()))
|
||||
.build();
|
||||
|
||||
EmbeddingResponse response = withRetryMappingExceptions(() -> client.embed((request)), maxRetries);
|
||||
|
||||
List<Embedding> embeddings = response.getEmbeddings()
|
||||
.stream()
|
||||
.map(Embedding::from)
|
||||
.collect(toList());
|
||||
List<Embedding> embeddings =
|
||||
response.getEmbeddings().stream().map(Embedding::from).collect(toList());
|
||||
|
||||
return Response.from(embeddings);
|
||||
}
|
||||
|
|
@ -80,8 +74,7 @@ public class OvhAiEmbeddingModel implements EmbeddingModel {
|
|||
private Boolean logResponses;
|
||||
private Logger logger;
|
||||
|
||||
OvhAiEmbeddingModelBuilder() {
|
||||
}
|
||||
OvhAiEmbeddingModelBuilder() {}
|
||||
|
||||
public OvhAiEmbeddingModelBuilder baseUrl(String baseUrl) {
|
||||
this.baseUrl = baseUrl;
|
||||
|
|
@ -127,7 +120,10 @@ public class OvhAiEmbeddingModel implements EmbeddingModel {
|
|||
}
|
||||
|
||||
public String toString() {
|
||||
return "OvhAiEmbeddingModel.OvhAiEmbeddingModelBuilder(baseUrl=" + this.baseUrl + ", apiKey=" + this.apiKey + ", timeout=" + this.timeout + ", maxRetries=" + this.maxRetries + ", logRequests=" + this.logRequests + ", logResponses=" + this.logResponses + ")";
|
||||
return "OvhAiEmbeddingModel.OvhAiEmbeddingModelBuilder(baseUrl=" + this.baseUrl + ", apiKey="
|
||||
+ (this.apiKey == null ? null : "********") + ", timeout=" + this.timeout + ", maxRetries="
|
||||
+ this.maxRetries + ", logRequests=" + this.logRequests + ", logResponses=" + this.logResponses
|
||||
+ ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
package dev.langchain4j.model.ovhai;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class OvhAiEmbeddingModelTest {
|
||||
|
||||
@Test
|
||||
void toString_should_mask_api_key() {
|
||||
String toString = OvhAiEmbeddingModel.builder().apiKey("secret-api-key").toString();
|
||||
|
||||
assertThat(toString).doesNotContain("secret-api-key").contains("apiKey=********");
|
||||
}
|
||||
|
||||
@Test
|
||||
void toString_should_render_null_api_key_as_null() {
|
||||
String toString = new OvhAiEmbeddingModel.OvhAiEmbeddingModelBuilder().toString();
|
||||
|
||||
assertThat(toString).contains("apiKey=null");
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue