Finish functionality

This commit is contained in:
Oracle 2026-04-26 18:21:05 +02:00
parent b6af1c9792
commit 89d5282b0f
Signed by: Oracle
SSH key fingerprint: SHA256:x4/RtnjUyuHkdvmwNDsWSfcfF1V5PNr3OpriZqOvCX8
9 changed files with 583 additions and 133 deletions

View file

@ -36,7 +36,7 @@ class SecureCompletionClientE2ETest {
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("E2E: Generate keys, save to disk, load in new client, validate")
void e2e_fullLifecycle_generateSaveLoadValidate() {
void e2e_fullLifecycle_generateSaveLoadValidate() throws Exception {
// Step 1: Generate keys and save to disk
SecureCompletionClient generateClient = new SecureCompletionClient(BASE_URL, false, true, 2);
generateClient.generateKeys(true, keyDir.getAbsolutePath(), TEST_PASSWORD);
@ -77,7 +77,7 @@ class SecureCompletionClientE2ETest {
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("E2E: Generate plaintext keys, load, and validate")
void e2e_plaintextKeys_generateLoadValidate() {
void e2e_plaintextKeys_generateLoadValidate() throws Exception {
// Generate plaintext keys (no password)
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(true, keyDir.getAbsolutePath(), null);
@ -296,7 +296,7 @@ class SecureCompletionClientE2ETest {
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("E2E: Encrypted key file is unreadable without password")
@DisplayName("E2E: Encrypted key file throws SecurityError without correct password")
void e2e_encryptedKey_unreadableWithoutPassword() throws Exception {
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(true, keyDir.getAbsolutePath(), TEST_PASSWORD);
@ -308,17 +308,19 @@ class SecureCompletionClientE2ETest {
assertFalse(encryptedContent.contains("BEGIN PRIVATE KEY"),
"Encrypted file should not contain PEM header");
// Try loading with wrong password - should not throw
// Try loading with wrong password - should throw SecurityError
SecureCompletionClient loadClient = new SecureCompletionClient();
assertDoesNotThrow(() ->
SecurityError error = assertThrows(SecurityError.class, () ->
loadClient.loadKeys(privateKeyFile.getAbsolutePath(), null, "wrong-password"),
"Wrong password should be handled gracefully"
"Wrong password should throw SecurityError"
);
assertTrue(error.getMessage().contains("decrypt") || error.getMessage().contains("password"),
"Error message should mention decryption or password");
}
@Test
@DisplayName("E2E: Generate keys without saving produces in-memory keys")
void e2e_generateKeys_noSave_producesInMemoryKeys() {
void e2e_generateKeys_noSave_producesInMemoryKeys() throws SecurityError {
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(false);

View file

@ -28,7 +28,7 @@ class SecureCompletionClientTest {
@Test
@DisplayName("generateKeys should create 4096-bit RSA key pair")
void generateKeys_shouldCreateValidKeyPair() {
void generateKeys_shouldCreateValidKeyPair() throws SecurityError {
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(false);
@ -58,7 +58,7 @@ class SecureCompletionClientTest {
@Test
@DisplayName("generateKeys should create unique keys on each call")
void generateKeys_shouldProduceUniqueKeys() {
void generateKeys_shouldProduceUniqueKeys() throws SecurityError {
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(false);
PrivateKey firstKey = client.getPrivateKey();
@ -76,7 +76,7 @@ class SecureCompletionClientTest {
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("generateKeys with saveToFile=true should create key files")
void generateKeys_withSaveToFile_shouldCreateKeyFiles(@TempDir Path tempDir) {
void generateKeys_withSaveToFile_shouldCreateKeyFiles(@TempDir Path tempDir) throws SecurityError {
File keyDir = tempDir.toFile();
SecureCompletionClient client = new SecureCompletionClient();
@ -112,7 +112,7 @@ class SecureCompletionClientTest {
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("generateKeys should not overwrite existing key files")
void generateKeys_shouldNotOverwriteExistingKeys(@TempDir Path tempDir) {
void generateKeys_shouldNotOverwriteExistingKeys(@TempDir Path tempDir) throws SecurityError {
File keyDir = tempDir.toFile();
SecureCompletionClient client = new SecureCompletionClient();
@ -129,10 +129,10 @@ class SecureCompletionClientTest {
// Key Loading Tests
@Test
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("loadKeys should load plaintext private key from file")
void loadKeys_plaintext_shouldLoadPrivateKey(@TempDir Path tempDir) {
void loadKeys_plaintext_shouldLoadPrivateKey(@TempDir Path tempDir) throws Exception {
File keyDir = tempDir.toFile();
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(true, keyDir.getAbsolutePath(), null);
@ -151,10 +151,10 @@ class SecureCompletionClientTest {
"Loaded key should have same size as original");
}
@Test
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("loadKeys should load encrypted private key with correct password")
void loadKeys_encrypted_correctPassword_shouldLoadPrivateKey(@TempDir Path tempDir) {
void loadKeys_encrypted_correctPassword_shouldLoadPrivateKey(@TempDir Path tempDir) throws Exception {
File keyDir = tempDir.toFile();
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(true, keyDir.getAbsolutePath(), TEST_PASSWORD);
@ -176,30 +176,33 @@ class SecureCompletionClientTest {
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("loadKeys should handle wrong password gracefully")
void loadKeys_encrypted_wrongPassword_shouldHandleGracefully(@TempDir Path tempDir) {
@DisplayName("loadKeys should throw SecurityError for wrong password")
void loadKeys_encrypted_wrongPassword_shouldThrowSecurityError(@TempDir Path tempDir) throws SecurityError {
File keyDir = tempDir.toFile();
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(true, keyDir.getAbsolutePath(), TEST_PASSWORD);
SecureCompletionClient loadClient = new SecureCompletionClient();
assertDoesNotThrow(() ->
SecurityError error = assertThrows(SecurityError.class, () ->
loadClient.loadKeys(
new File(keyDir, Constants.DEFAULT_PRIVATE_KEY_FILE).getAbsolutePath(),
null,
"wrong-password"
),
"Wrong password should not throw exception"
"Wrong password should throw SecurityError"
);
assertTrue(error.getMessage().contains("decrypt") || error.getMessage().contains("password"),
"Error message should mention decryption or password");
}
@Test
@DisplayName("loadKeys should throw exception for non-existent file")
void loadKeys_nonExistentFile_shouldThrowException() {
void loadKeys_nonExistentFile_shouldThrowException() {
SecureCompletionClient loadClient = new SecureCompletionClient();
RuntimeException error = assertThrows(RuntimeException.class, () ->
SecurityError error = assertThrows(SecurityError.class, () ->
loadClient.loadKeys("/non/existent/path/private_key.pem", null, null));
assertTrue(error.getMessage().contains("not found"),
@ -210,7 +213,7 @@ class SecureCompletionClientTest {
@Test
@DisplayName("validateRsaKey should accept valid 4096-bit key")
void validateRsaKey_validKey_shouldPass() {
void validateRsaKey_validKey_shouldPass() throws SecurityError {
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(false);
PrivateKey key = client.getPrivateKey();
@ -264,7 +267,7 @@ class SecureCompletionClientTest {
@Test
@Execution(ExecutionMode.SAME_THREAD)
@DisplayName("Full roundtrip: generate, save, load should produce same key")
void roundtrip_generateSaveLoad_shouldProduceSameKey(@TempDir Path tempDir) {
void roundtrip_generateSaveLoad_shouldProduceSameKey(@TempDir Path tempDir) throws Exception {
File keyDir = tempDir.toFile();
// Generate and save
@ -407,10 +410,6 @@ class SecureCompletionClientTest {
tempClient.generateKeys(false);
PrivateKey originalKey = tempClient.getPrivateKey();
String pem = "-----BEGIN PRIVATE KEY-----\n " +
originalKey.getEncoded().length + "lines\n" +
"-----END PRIVATE KEY-----";
String formattedPem = ai.nomyo.util.PEMConverter.toPEM(originalKey.getEncoded(), true);
String pemWithWhitespace = formattedPem.replace("\n", "\n ");