From 6e6712083391a0bdd3188aeb35b260dd9ab3f0bd Mon Sep 17 00:00:00 2001 From: Akihiro Nishikawa Date: Sun, 14 Jun 2026 10:02:56 +0900 Subject: [PATCH 1/6] Step 3: Upgrade to Java 25 + align Azure SDK - Compile: SUCCESS - Set maven.compiler.release=25 (was source/target 8) - Align Azure SDK via azure-sdk-bom 1.3.7; remove unused legacy azure-keyvault-core - Rename azure-keyvault-keys -> azure-security-keyvault-keys (BOM-managed versions) - Upgrade Maven plugins: compiler 3.13.0, surefire 3.5.2, dependency 3.8.1, resources 3.3.1, jar 3.4.2 - App.java: identity imports -> com.azure.identity.*; cipherText()/plainText() -> getCipherText()/getPlainText() - Security: upgraded Azure SDK from 2019 preview to current GA, reducing known-CVE exposure; auth flow unchanged --- .gitignore | 23 +++++++++++++++++++ pom.xml | 36 +++++++++++++++++------------- src/main/java/kvsdk4java2/App.java | 16 ++++++------- 3 files changed, 51 insertions(+), 24 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42bec0e --- /dev/null +++ b/.gitignore @@ -0,0 +1,23 @@ +# Maven +target/ + +# Java +*.class + +# Logs +*.log + +# IntelliJ IDEA +.idea/ +*.iml + +# Eclipse +.classpath +.project +.settings/ + +# VS Code +.vscode/ + +# macOS +.DS_Store \ No newline at end of file diff --git a/pom.xml b/pom.xml index 0f4e998..563fa01 100644 --- a/pom.xml +++ b/pom.xml @@ -14,33 +14,37 @@ UTF-8 UTF-8 - 8 - ${maven.compiler.source} + 25 + 1.3.7 libs ${project.build.directory}/${libs.classpath.prefix} kvsdk4java2.App + + + + com.azure + azure-sdk-bom + ${azure.sdk.bom.version} + pom + import + + + + - - com.microsoft.azure - azure-keyvault-core - 1.2.2 - com.azure - azure-keyvault-keys - 4.0.0-preview.3 + azure-security-keyvault-keys com.azure azure-identity - 1.12.2 com.azure azure-core-http-netty - 1.0.0-preview.4 @@ -51,27 +55,27 @@ org.apache.maven.plugins maven-compiler-plugin - 3.8.0 + 3.13.0 org.apache.maven.plugins maven-surefire-plugin - 2.22.1 + 3.5.2 org.apache.maven.plugins maven-dependency-plugin - 3.1.1 + 3.8.1 org.apache.maven.plugins maven-resources-plugin - 3.0.2 + 3.3.1 org.apache.maven.plugins maven-jar-plugin - 3.0.2 + 3.4.2 diff --git a/src/main/java/kvsdk4java2/App.java b/src/main/java/kvsdk4java2/App.java index 804d7e6..79361c0 100644 --- a/src/main/java/kvsdk4java2/App.java +++ b/src/main/java/kvsdk4java2/App.java @@ -1,7 +1,7 @@ package kvsdk4java2; -import com.azure.identity.credential.ClientSecretCredential; -import com.azure.identity.credential.ClientSecretCredentialBuilder; +import com.azure.identity.ClientSecretCredential; +import com.azure.identity.ClientSecretCredentialBuilder; import com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient; import com.azure.security.keyvault.keys.cryptography.CryptographyClient; import com.azure.security.keyvault.keys.cryptography.CryptographyClientBuilder; @@ -38,10 +38,10 @@ public static void main(String[] args) { log.info("[textToEncrypt]" + textToEncrypt); byte[] byteText = textToEncrypt.getBytes(StandardCharsets.UTF_16); EncryptResult encryptResult1 = cryptographyClient.encrypt(EncryptionAlgorithm.RSA_OAEP, byteText); - log.info("[Encrypted]" + new String(encryptResult1.cipherText(), StandardCharsets.UTF_16)); + log.info("[Encrypted]" + new String(encryptResult1.getCipherText(), StandardCharsets.UTF_16)); - DecryptResult decryptResult1 = cryptographyClient.decrypt(EncryptionAlgorithm.RSA_OAEP, encryptResult1.cipherText()); - log.info("[Decrypted]" + textToEncrypt + "<===>" + new String(decryptResult1.plainText(), StandardCharsets.UTF_16)); + DecryptResult decryptResult1 = cryptographyClient.decrypt(EncryptionAlgorithm.RSA_OAEP, encryptResult1.getCipherText()); + log.info("[Decrypted]" + textToEncrypt + "<===>" + new String(decryptResult1.getPlainText(), StandardCharsets.UTF_16)); log.info("---Async---"); @@ -54,11 +54,11 @@ public static void main(String[] args) { EncryptResult encryptResult2 = cryptographyAsyncClient .encrypt(EncryptionAlgorithm.RSA_OAEP, byteText) .block(); - log.info("[Encrypted]" + new String(encryptResult2.cipherText(), StandardCharsets.UTF_16)); + log.info("[Encrypted]" + new String(encryptResult2.getCipherText(), StandardCharsets.UTF_16)); DecryptResult decryptResult2 = cryptographyAsyncClient - .decrypt(EncryptionAlgorithm.RSA_OAEP, encryptResult2.cipherText()) + .decrypt(EncryptionAlgorithm.RSA_OAEP, encryptResult2.getCipherText()) .block(); - log.info("[Decrypted]" + textToEncrypt + "<=======>" + new String(decryptResult2.plainText(), StandardCharsets.UTF_16)); + log.info("[Decrypted]" + textToEncrypt + "<=======>" + new String(decryptResult2.getPlainText(), StandardCharsets.UTF_16)); } } From a9e0fd0b53f732f07e7675785b23bf2d341d8ab1 Mon Sep 17 00:00:00 2001 From: Akihiro Nishikawa Date: Sun, 14 Jun 2026 10:14:44 +0900 Subject: [PATCH 2/6] Step 5: Final Validation - Compile: SUCCESS, Tests: no tests (pass) - Fix maven-dependency-plugin 3.8.1 copy-dependencies config: remove invalid excludeScope=test (redundant with includeScope=runtime) and a duplicate overWriteIfNewer line - mvn clean verify passes on JDK 25; bytecode major version 69 (Java 25) - Runnable jar target/keyvaultclient2.jar + 45 dependency jars in target/libs produced --- .gitignore | 4 +++- pom.xml | 2 -- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index 42bec0e..72565ce 100644 --- a/.gitignore +++ b/.gitignore @@ -20,4 +20,6 @@ target/ .vscode/ # macOS -.DS_Store \ No newline at end of file +.DS_Store + +.github/modernize \ No newline at end of file diff --git a/pom.xml b/pom.xml index 563fa01..99a41cc 100644 --- a/pom.xml +++ b/pom.xml @@ -105,9 +105,7 @@ false false true - true runtime - test From 7941d4405247836a7a700ac35972c87738cd68e6 Mon Sep 17 00:00:00 2001 From: Akihiro Nishikawa Date: Sun, 14 Jun 2026 10:17:39 +0900 Subject: [PATCH 3/6] docs: add upgrade summary and finalize progress tracking (session 20260614005200) - Add summary.md for the Java 8 -> 25 upgrade - Record commit hashes in progress.md for steps 3 and 5 --- .gitignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.gitignore b/.gitignore index 72565ce..c1aebfb 100644 --- a/.gitignore +++ b/.gitignore @@ -21,5 +21,3 @@ target/ # macOS .DS_Store - -.github/modernize \ No newline at end of file From 616309a565396954b67f287ee895d713e83a2686 Mon Sep 17 00:00:00 2001 From: Akihiro Nishikawa Date: Sun, 14 Jun 2026 10:27:28 +0900 Subject: [PATCH 4/6] test: add AppTest covering App.main() with mocked Azure SDK - Add src/test/java/kvsdk4java2/AppTest.java: uses Mockito mockConstruction to replace Azure SDK builders/clients, exercising the sync + async encrypt/decrypt flow with no network or credentials - pom.xml: add JUnit 5 (junit-jupiter 5.11.4) and Mockito (mockito-core/junit-jupiter 5.23.0) test-scope deps; add surefire argLine -Dnet.bytebuddy.experimental=true for ByteBuddy on JDK 25 - mvn clean verify on JDK 25: BUILD SUCCESS, Tests run: 1, Failures: 0, Errors: 0 --- pom.xml | 26 ++++++++ src/test/java/kvsdk4java2/AppTest.java | 89 ++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 src/test/java/kvsdk4java2/AppTest.java diff --git a/pom.xml b/pom.xml index 99a41cc..0f7ce07 100644 --- a/pom.xml +++ b/pom.xml @@ -46,6 +46,25 @@ com.azure azure-core-http-netty + + + org.junit.jupiter + junit-jupiter + 5.11.4 + test + + + org.mockito + mockito-core + 5.23.0 + test + + + org.mockito + mockito-junit-jupiter + 5.23.0 + test + @@ -110,6 +129,13 @@ + + org.apache.maven.plugins + maven-surefire-plugin + + -Dnet.bytebuddy.experimental=true + + diff --git a/src/test/java/kvsdk4java2/AppTest.java b/src/test/java/kvsdk4java2/AppTest.java new file mode 100644 index 0000000..f151e8b --- /dev/null +++ b/src/test/java/kvsdk4java2/AppTest.java @@ -0,0 +1,89 @@ +package kvsdk4java2; + +import com.azure.identity.ClientSecretCredential; +import com.azure.identity.ClientSecretCredentialBuilder; +import com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient; +import com.azure.security.keyvault.keys.cryptography.CryptographyClient; +import com.azure.security.keyvault.keys.cryptography.CryptographyClientBuilder; +import com.azure.security.keyvault.keys.cryptography.models.DecryptResult; +import com.azure.security.keyvault.keys.cryptography.models.EncryptResult; +import com.azure.security.keyvault.keys.cryptography.models.EncryptionAlgorithm; +import org.junit.jupiter.api.Test; +import org.mockito.MockedConstruction; +import reactor.core.publisher.Mono; + +import java.nio.charset.StandardCharsets; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockConstruction; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +/** + * Unit tests for {@link App}. + * + *

{@code App.main} constructs Azure Key Vault clients internally and performs encrypt/decrypt + * round-trips. To exercise that code path without any network/credential dependency, all Azure SDK + * builders and clients are replaced with Mockito mocks via {@code mockConstruction}. No production + * source is modified. + */ +class AppTest { + + @Test + void mainRunsEncryptDecryptRoundTripWithMockedKeyVaultClients() { + // Arrange: canned crypto results returned by the mocked clients. + byte[] cipher = "cipher-bytes".getBytes(StandardCharsets.UTF_16); + byte[] plain = "This is a test".getBytes(StandardCharsets.UTF_16); + + EncryptResult encryptResult = mock(EncryptResult.class); + when(encryptResult.getCipherText()).thenReturn(cipher); + DecryptResult decryptResult = mock(DecryptResult.class); + when(decryptResult.getPlainText()).thenReturn(plain); + + CryptographyClient syncClient = mock(CryptographyClient.class); + when(syncClient.encrypt(any(EncryptionAlgorithm.class), any(byte[].class))).thenReturn(encryptResult); + when(syncClient.decrypt(any(EncryptionAlgorithm.class), any(byte[].class))).thenReturn(decryptResult); + + CryptographyAsyncClient asyncClient = mock(CryptographyAsyncClient.class); + when(asyncClient.encrypt(any(EncryptionAlgorithm.class), any(byte[].class))).thenReturn(Mono.just(encryptResult)); + when(asyncClient.decrypt(any(EncryptionAlgorithm.class), any(byte[].class))).thenReturn(Mono.just(decryptResult)); + + ClientSecretCredential credential = mock(ClientSecretCredential.class); + + try (MockedConstruction credentialBuilders = mockConstruction( + ClientSecretCredentialBuilder.class, + (builder, context) -> { + when(builder.clientId(any())).thenReturn(builder); + when(builder.clientSecret(any())).thenReturn(builder); + when(builder.tenantId(any())).thenReturn(builder); + when(builder.build()).thenReturn(credential); + }); + MockedConstruction cryptoBuilders = mockConstruction( + CryptographyClientBuilder.class, + (builder, context) -> { + when(builder.credential(any())).thenReturn(builder); + when(builder.keyIdentifier(any())).thenReturn(builder); + when(builder.buildClient()).thenReturn(syncClient); + when(builder.buildAsyncClient()).thenReturn(asyncClient); + })) { + + // Act + App.main(new String[]{}); + + // Assert: one credential builder, two cryptography builders (sync + async) were created. + assertEquals(1, credentialBuilders.constructed().size()); + assertEquals(2, cryptoBuilders.constructed().size()); + + // The synchronous path encrypts then decrypts exactly once. + verify(syncClient, times(1)).encrypt(any(EncryptionAlgorithm.class), any(byte[].class)); + verify(syncClient, times(1)).decrypt(any(EncryptionAlgorithm.class), any(byte[].class)); + + // The asynchronous path encrypts then decrypts exactly once. + verify(asyncClient, times(1)).encrypt(any(EncryptionAlgorithm.class), any(byte[].class)); + verify(asyncClient, times(1)).decrypt(any(EncryptionAlgorithm.class), any(byte[].class)); + } + } +} From e261a05ae1a93733e857707c6855e6776f7d3a2c Mon Sep 17 00:00:00 2001 From: Akihiro Nishikawa Date: Sun, 14 Jun 2026 12:06:37 +0900 Subject: [PATCH 5/6] refactor: reorder imports for consistency in App.java and AppTest.java --- pom.xml | 9 +++++++-- src/main/java/kvsdk4java2/App.java | 6 +++--- src/test/java/kvsdk4java2/AppTest.java | 25 +++++++++++++------------ 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/pom.xml b/pom.xml index 0f7ce07..6cabeed 100644 --- a/pom.xml +++ b/pom.xml @@ -14,8 +14,13 @@ UTF-8 UTF-8 - 25 - 1.3.7 + 25 + 4.11.0 + 1.18.3 + 3.5.0 + 3.15.0 + 5.23.0 + 6.1.0 libs ${project.build.directory}/${libs.classpath.prefix} kvsdk4java2.App diff --git a/src/main/java/kvsdk4java2/App.java b/src/main/java/kvsdk4java2/App.java index 79361c0..9072d7e 100644 --- a/src/main/java/kvsdk4java2/App.java +++ b/src/main/java/kvsdk4java2/App.java @@ -1,5 +1,8 @@ package kvsdk4java2; +import java.nio.charset.StandardCharsets; +import java.util.logging.Logger; + import com.azure.identity.ClientSecretCredential; import com.azure.identity.ClientSecretCredentialBuilder; import com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient; @@ -9,9 +12,6 @@ import com.azure.security.keyvault.keys.cryptography.models.EncryptResult; import com.azure.security.keyvault.keys.cryptography.models.EncryptionAlgorithm; -import java.nio.charset.StandardCharsets; -import java.util.logging.Logger; - public class App { static final String AZURE_CLIENT_ID = "Client ID"; diff --git a/src/test/java/kvsdk4java2/AppTest.java b/src/test/java/kvsdk4java2/AppTest.java index f151e8b..2b71986 100644 --- a/src/test/java/kvsdk4java2/AppTest.java +++ b/src/test/java/kvsdk4java2/AppTest.java @@ -1,27 +1,28 @@ package kvsdk4java2; -import com.azure.identity.ClientSecretCredential; -import com.azure.identity.ClientSecretCredentialBuilder; -import com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient; -import com.azure.security.keyvault.keys.cryptography.CryptographyClient; -import com.azure.security.keyvault.keys.cryptography.CryptographyClientBuilder; -import com.azure.security.keyvault.keys.cryptography.models.DecryptResult; -import com.azure.security.keyvault.keys.cryptography.models.EncryptResult; -import com.azure.security.keyvault.keys.cryptography.models.EncryptionAlgorithm; -import org.junit.jupiter.api.Test; -import org.mockito.MockedConstruction; -import reactor.core.publisher.Mono; - import java.nio.charset.StandardCharsets; import static org.junit.jupiter.api.Assertions.assertEquals; +import org.junit.jupiter.api.Test; import static org.mockito.ArgumentMatchers.any; +import org.mockito.MockedConstruction; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mockConstruction; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import com.azure.identity.ClientSecretCredential; +import com.azure.identity.ClientSecretCredentialBuilder; +import com.azure.security.keyvault.keys.cryptography.CryptographyAsyncClient; +import com.azure.security.keyvault.keys.cryptography.CryptographyClient; +import com.azure.security.keyvault.keys.cryptography.CryptographyClientBuilder; +import com.azure.security.keyvault.keys.cryptography.models.DecryptResult; +import com.azure.security.keyvault.keys.cryptography.models.EncryptResult; +import com.azure.security.keyvault.keys.cryptography.models.EncryptionAlgorithm; + +import reactor.core.publisher.Mono; + /** * Unit tests for {@link App}. * From 7ad5c278a2ea38a4899b25c703662128018d12d4 Mon Sep 17 00:00:00 2001 From: Akihiro Nishikawa Date: Sun, 14 Jun 2026 12:14:45 +0900 Subject: [PATCH 6/6] chore: update Maven plugin versions and replace hardcoded values with properties in pom.xml --- pom.xml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/pom.xml b/pom.xml index 6cabeed..635ad3d 100644 --- a/pom.xml +++ b/pom.xml @@ -19,6 +19,10 @@ 1.18.3 3.5.0 3.15.0 + 3.5.6 + 3.11.0 + 3.5.0 + 3.5.0 5.23.0 6.1.0 libs @@ -55,19 +59,19 @@ org.junit.jupiter junit-jupiter - 5.11.4 + ${junit.jupiter.version} test org.mockito mockito-core - 5.23.0 + ${mockito.core.version} test org.mockito mockito-junit-jupiter - 5.23.0 + ${mockito.core.version} test @@ -79,27 +83,27 @@ org.apache.maven.plugins maven-compiler-plugin - 3.13.0 + ${maven.compiler.plugin.version} org.apache.maven.plugins maven-surefire-plugin - 3.5.2 + ${maven.surefire.plugin.version} org.apache.maven.plugins maven-dependency-plugin - 3.8.1 + ${maven.dependency.plugin.version} org.apache.maven.plugins maven-resources-plugin - 3.3.1 + ${maven.resources.plugin.version} org.apache.maven.plugins maven-jar-plugin - 3.4.2 + ${maven.jar.plugin.version}