mirror of
https://gitlab.rlp.net/proj-wise2526-video2document/video2document.git
synced 2026-06-15 18:01:52 +02:00
Update 6 files
- /src1/main/resources/application.yml - /src1/main/java/com/v2d/document/config/AppProperties.java - /src1/main/java/com/v2d/document/service/ExternalApiService.java - /src1/main/java/com/v2d/document/controller/GenerateController.java - /src1/test/AppPropertiesTest.java - /README.md
This commit is contained in:
parent
283b4ed6af
commit
55555bcc37
@@ -91,3 +91,46 @@ For open source projects, say how it is licensed.
|
|||||||
|
|
||||||
## Project status
|
## Project status
|
||||||
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.
|
||||||
|
## 🔐 Secure API Key Management (Sprint 4 – V2D Document)
|
||||||
|
|
||||||
|
This project uses secure environment variables to store and manage all external API keys
|
||||||
|
(required for LLM/Transcription APIs). No API key is ever committed into the repository.
|
||||||
|
|
||||||
|
### ✔ How the API Key Works
|
||||||
|
The application reads the key from an environment variable named:
|
||||||
|
|
||||||
|
`LLM_API_KEY`
|
||||||
|
|
||||||
|
Spring Boot loads it automatically using the following configuration in `application.yml`:
|
||||||
|
|
||||||
|
|
||||||
|
### ✔ Local Development (developer machines)
|
||||||
|
Developers must manually set their API key locally:
|
||||||
|
|
||||||
|
|
||||||
|
### ✔ GitLab CI/CD Setup (secure by default)
|
||||||
|
To provide the key for all environments securely:
|
||||||
|
|
||||||
|
1. Go to **GitLab → Settings → CI/CD → Variables**
|
||||||
|
2. Add variable:
|
||||||
|
- **Key:** `LLM_API_KEY`
|
||||||
|
- **Value:** your real API key
|
||||||
|
- **Masked:** ✓ Enable
|
||||||
|
- **Protected:** (optional)
|
||||||
|
3. Save.
|
||||||
|
|
||||||
|
Pipelines will automatically use the secure key without exposing it.
|
||||||
|
|
||||||
|
### ✔ Security Guarantees
|
||||||
|
- The API key is **not stored** in the repository
|
||||||
|
- `.env` files are ignored through `.gitignore`
|
||||||
|
- The key is **never printed**, logged, or exposed to users
|
||||||
|
- Every new user of V2D Document can use the system **without needing their own key**
|
||||||
|
|
||||||
|
### ✔ Files Added in This User Story
|
||||||
|
- `src/main/resources/application.yml`
|
||||||
|
- `src/main/java/com/v2d/document/config/AppProperties.java`
|
||||||
|
- `src/main/java/com/v2d/document/service/ExternalApiService.java`
|
||||||
|
- `src/test/java/com/v2d/document/config/AppPropertiesTest.java`
|
||||||
|
|
||||||
|
This completes Sprint 4 User Story: **Backend – Secure Management & Storage of API Keys**.
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package com.v2d.document.config;
|
||||||
|
|
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ConfigurationProperties(prefix = "app.external")
|
||||||
|
public class AppProperties {
|
||||||
|
private String apiKey;
|
||||||
|
|
||||||
|
public String getApiKey() { return apiKey; }
|
||||||
|
public void setApiKey(String apiKey) { this.apiKey = apiKey; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package com.v2d.document.controller;
|
||||||
|
|
||||||
|
import com.v2d.document.service.ExternalApiService;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/api/generate")
|
||||||
|
public class GenerateController {
|
||||||
|
|
||||||
|
private final ExternalApiService externalApiService;
|
||||||
|
|
||||||
|
public GenerateController(ExternalApiService externalApiService) {
|
||||||
|
this.externalApiService = externalApiService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@PostMapping
|
||||||
|
public ResponseEntity<String> generate(@RequestBody Map<String,Object> body) {
|
||||||
|
// Build provider payload from the user's body (transform safely)
|
||||||
|
String payload = "{\"text\": \"use this text\"}"; // adapt for real usage
|
||||||
|
String providerResponse = externalApiService.callProvider(payload);
|
||||||
|
return ResponseEntity.ok(providerResponse);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package com.v2d.document.service;
|
||||||
|
|
||||||
|
import com.v2d.document.config.AppProperties;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.http.HttpClient;
|
||||||
|
import java.net.http.HttpRequest;
|
||||||
|
import java.net.http.HttpResponse;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
public class ExternalApiService {
|
||||||
|
private final Logger log = LoggerFactory.getLogger(ExternalApiService.class);
|
||||||
|
private final AppProperties props;
|
||||||
|
private final HttpClient http = HttpClient.newHttpClient();
|
||||||
|
|
||||||
|
public ExternalApiService(AppProperties props) {
|
||||||
|
this.props = props;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String callProvider(String jsonPayload) {
|
||||||
|
String key = props.getApiKey();
|
||||||
|
if (key == null || key.isBlank()) {
|
||||||
|
log.warn("External API key is not configured.");
|
||||||
|
throw new IllegalStateException("External API key missing");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
HttpRequest req = HttpRequest.newBuilder()
|
||||||
|
.uri(URI.create("https://api.example.com/endpoint")) // replace with real endpoint
|
||||||
|
.header("Authorization", "Bearer " + key)
|
||||||
|
.header("Content-Type", "application/json")
|
||||||
|
.POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
HttpResponse<String> resp = http.send(req, HttpResponse.BodyHandlers.ofString());
|
||||||
|
return resp.body();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("External API call failed: {}", e.getMessage());
|
||||||
|
throw new RuntimeException("External API call failed", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
spring:
|
||||||
|
application:
|
||||||
|
name: v2d-document
|
||||||
|
|
||||||
|
app:
|
||||||
|
external:
|
||||||
|
apiKey: ${LLM_API_KEY:}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package com.v2d.document.config;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
public class AppPropertiesTest {
|
||||||
|
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
|
||||||
|
.withUserConfiguration(AppProperties.class)
|
||||||
|
.withPropertyValues("app.external.apiKey=TEST_KEY");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void bindsApiKey() {
|
||||||
|
contextRunner.run(context -> {
|
||||||
|
AppProperties props = context.getBean(AppProperties.class);
|
||||||
|
assertThat(props.getApiKey()).isEqualTo("TEST_KEY");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user