This is an automated email from the ASF dual-hosted git repository.

oscerd pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git


The following commit(s) were added to refs/heads/main by this push:
     new 59a3f12aba26 CAMEL-22887: camel-cyberark-vault - add test-infra for 
automated testing (#25096)
59a3f12aba26 is described below

commit 59a3f12aba26490ab3369fe5d992fac8dbe61b36
Author: Andrea Cosentino <[email protected]>
AuthorDate: Sat Jul 25 08:53:31 2026 +0200

    CAMEL-22887: camel-cyberark-vault - add test-infra for automated testing 
(#25096)
    
    Conjur cannot run standalone, so camel-test-infra-cyberark-vault starts
    both a Conjur server and its PostgreSQL backend on a private network,
    then creates the Conjur account and captures the generated admin API key.
    
    The integration tests no longer need a manually provisioned Conjur and a
    set of system properties, so the @EnabledIfSystemProperty gates are gone
    and the tests actually run.
    
    The cyberark/conjur image is only published for amd64 and arm64, so the
    ITs are disabled on ppc64le and s390x.
    
    Co-authored-by: Claude Opus 4.8 (1M context) <[email protected]>
---
 .../apache/camel/catalog/test-infra/metadata.json  |  11 +
 components/camel-cyberark-vault/pom.xml            |  25 +-
 .../vault/integration/CyberArkTestSupport.java     |  34 +-
 .../CyberArkVaultMultipleSecretsIT.java            |  49 +--
 .../vault/integration/CyberArkVaultProducerIT.java |  29 +-
 .../CyberArkVaultPropertiesSourceIT.java           |  75 +---
 .../component/cyberark/vault/integration/README.md | 418 ++++-----------------
 test-infra/camel-test-infra-all/pom.xml            |  11 +
 .../src/generated/resources/META-INF/metadata.json |  11 +
 test-infra/camel-test-infra-cyberark-vault/pom.xml |  46 +++
 .../vault/common/CyberArkVaultProperties.java      |  34 ++
 .../vault/services/CyberArkVaultInfraService.java  |  55 +++
 .../CyberArkVaultLocalContainerInfraService.java   | 247 ++++++++++++
 .../vault/services/CyberArkVaultService.java       |  26 ++
 .../services/CyberArkVaultServiceFactory.java      |  39 ++
 .../src/main/resources/META-INF/MANIFEST.MF        |   0
 .../cyberark/vault/services/container.properties   |  24 ++
 test-infra/pom.xml                                 |   1 +
 18 files changed, 642 insertions(+), 493 deletions(-)

diff --git 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
index a1b236ed29ce..c73de002b73d 100644
--- 
a/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
+++ 
b/catalog/camel-catalog/src/generated/resources/org/apache/camel/catalog/test-infra/metadata.json
@@ -339,6 +339,17 @@
   "version" : "4.22.0-SNAPSHOT",
   "serviceVersion" : "0.3",
   "uiSupported" : false
+}, {
+  "service" : 
"org.apache.camel.test.infra.cyberark.vault.services.CyberArkVaultInfraService",
+  "description" : "CyberArk Conjur is an open source secrets management 
solution",
+  "implementation" : 
"org.apache.camel.test.infra.cyberark.vault.services.CyberArkVaultLocalContainerInfraService",
+  "alias" : [ "cyberark" ],
+  "aliasImplementation" : [ "conjur" ],
+  "groupId" : "org.apache.camel",
+  "artifactId" : "camel-test-infra-cyberark-vault",
+  "version" : "4.22.0-SNAPSHOT",
+  "serviceVersion" : "1.24.0",
+  "uiSupported" : false
 }, {
   "service" : 
"org.apache.camel.test.infra.opensearch.services.OpenSearchInfraService",
   "description" : "OpenSearch is a distributed search and analytics engine",
diff --git a/components/camel-cyberark-vault/pom.xml 
b/components/camel-cyberark-vault/pom.xml
index 7d8d4399b6b2..afa0631a17e0 100644
--- a/components/camel-cyberark-vault/pom.xml
+++ b/components/camel-cyberark-vault/pom.xml
@@ -35,6 +35,9 @@
     <properties>
         <firstVersion>4.17.0</firstVersion>
         <label>cloud,security</label>
+        <!-- the cyberark/conjur image is only published for amd64 and arm64 
-->
+        <skipITs.ppc64le>true</skipITs.ppc64le>
+        <skipITs.s390x>true</skipITs.s390x>
     </properties>
 
     <dependencies>
@@ -64,21 +67,11 @@
            <scope>test</scope>
            <version>${mockito-version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-cyberark-vault</artifactId>
+            <version>${project.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <artifactId>maven-failsafe-plugin</artifactId>
-                <configuration>
-                    <systemPropertyVariables>
-                        
<camel.cyberark.url>http://localhost:8080</camel.cyberark.url>
-                        
<camel.cyberark.account>myConjurAccount</camel.cyberark.account>
-                        
<camel.cyberark.username>admin</camel.cyberark.username>
-                        
<!--camel.cyberark.apiKey>your-api-key</camel.cyberark.apiKey-->
-                    </systemPropertyVariables>
-                </configuration>
-            </plugin>
-        </plugins>
-    </build>
 </project>
diff --git 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkTestSupport.java
 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkTestSupport.java
index 99ef4f637057..6fc6ef50357f 100644
--- 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkTestSupport.java
+++ 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkTestSupport.java
@@ -26,14 +26,21 @@ import java.time.Duration;
 
 import org.apache.camel.EndpointInject;
 import org.apache.camel.component.mock.MockEndpoint;
+import 
org.apache.camel.test.infra.cyberark.vault.services.CyberArkVaultService;
+import 
org.apache.camel.test.infra.cyberark.vault.services.CyberArkVaultServiceFactory;
 import org.apache.camel.test.junit6.CamelTestSupport;
+import org.apache.camel.vault.CyberArkVaultConfiguration;
 import org.junit.jupiter.api.AfterAll;
 import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.extension.RegisterExtension;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 abstract class CyberArkTestSupport extends CamelTestSupport {
 
+    @RegisterExtension
+    static CyberArkVaultService service = 
CyberArkVaultServiceFactory.createService();
+
     static final Logger LOG = 
LoggerFactory.getLogger(CyberArkTestSupport.class);
 
     static HttpClient httpClient;
@@ -57,17 +64,28 @@ abstract class CyberArkTestSupport extends CamelTestSupport 
{
         httpClient = null;
     }
 
+    /**
+     * Points the context wide vault configuration at the Conjur instance 
started by the test infra.
+     */
+    void configureVault() {
+        CyberArkVaultConfiguration cyberark = 
context.getVaultConfiguration().cyberark();
+        cyberark.setUrl(service.url());
+        cyberark.setAccount(service.account());
+        cyberark.setUsername(service.username());
+        cyberark.setApiKey(service.apiKey());
+    }
+
     private static String authenticate() throws Exception {
         String url = String.format("%s/authn/%s/%s/authenticate",
-                System.getProperty("camel.cyberark.url"),
-                System.getProperty("camel.cyberark.account"),
-                System.getProperty("camel.cyberark.username"));
+                service.url(),
+                service.account(),
+                service.username());
 
         HttpRequest request = HttpRequest.newBuilder()
                 .uri(URI.create(url))
                 .header("Content-Type", "text/plain")
                 .header("Accept-Encoding", "base64")
-                
.POST(HttpRequest.BodyPublishers.ofString(System.getProperty("camel.cyberark.apiKey")))
+                .POST(HttpRequest.BodyPublishers.ofString(service.apiKey()))
                 .build();
 
         HttpResponse<String> response = httpClient.send(request, 
HttpResponse.BodyHandlers.ofString());
@@ -79,8 +97,8 @@ abstract class CyberArkTestSupport extends CamelTestSupport {
     static void loadPolicy(String policy) throws Exception {
 
         String policyUrl = String.format("%s/policies/%s/policy/%s",
-                System.getProperty("camel.cyberark.url"),
-                System.getProperty("camel.cyberark.account"),
+                service.url(),
+                service.account(),
                 URLEncoder.encode("root", StandardCharsets.UTF_8));
 
         HttpRequest request = HttpRequest.newBuilder()
@@ -96,8 +114,8 @@ abstract class CyberArkTestSupport extends CamelTestSupport {
 
     static void createSecret(String secretId, String secretValue) throws 
Exception {
         String url = String.format("%s/secrets/%s/variable/%s",
-                System.getProperty("camel.cyberark.url"),
-                System.getProperty("camel.cyberark.account"),
+                service.url(),
+                service.account(),
                 URLEncoder.encode(secretId, StandardCharsets.UTF_8));
 
         HttpRequest request = HttpRequest.newBuilder()
diff --git 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultMultipleSecretsIT.java
 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultMultipleSecretsIT.java
index 0840fa0251f8..793b4000bdd9 100644
--- 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultMultipleSecretsIT.java
+++ 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultMultipleSecretsIT.java
@@ -20,31 +20,14 @@ import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperties;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
 
 /**
  * Integration test demonstrating multiple secret retrieval in a single route
  */
-// Must be manually tested. Provide CyberArk Conjur connection details using 
system properties:
-// -Dcamel.cyberark.url=http://localhost:8080
-// -Dcamel.cyberark.account=myConjurAccount
-// -Dcamel.cyberark.username=admin
-// -Dcamel.cyberark.apiKey=your-api-key
-@EnabledIfSystemProperties({
-        @EnabledIfSystemProperty(named = "camel.cyberark.url", matches = ".*",
-                                 disabledReason = "CyberArk Conjur URL not 
provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.account", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur account not 
provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.username", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur username 
not provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.apiKey", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur API key not 
provided")
-})
-public class CyberArkVaultMultipleSecretsIT extends CyberArkTestSupport {
+class CyberArkVaultMultipleSecretsIT extends CyberArkTestSupport {
 
     @BeforeAll
-    public static void setupSecrets() throws Exception {
+    static void setupSecrets() throws Exception {
 
         // Declare variables
         loadPolicy("""
@@ -62,11 +45,8 @@ public class CyberArkVaultMultipleSecretsIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testMultipleSecretsInSingleRoute() throws Exception {
-        
context.getVaultConfiguration().cyberark().setUrl(System.getProperty("camel.cyberark.url"));
-        
context.getVaultConfiguration().cyberark().setAccount(System.getProperty("camel.cyberark.account"));
-        
context.getVaultConfiguration().cyberark().setUsername(System.getProperty("camel.cyberark.username"));
-        
context.getVaultConfiguration().cyberark().setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testMultipleSecretsInSingleRoute() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -93,11 +73,8 @@ public class CyberArkVaultMultipleSecretsIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testMultipleDatabaseConfigs() throws Exception {
-        
context.getVaultConfiguration().cyberark().setUrl(System.getProperty("camel.cyberark.url"));
-        
context.getVaultConfiguration().cyberark().setAccount(System.getProperty("camel.cyberark.account"));
-        
context.getVaultConfiguration().cyberark().setUsername(System.getProperty("camel.cyberark.username"));
-        
context.getVaultConfiguration().cyberark().setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testMultipleDatabaseConfigs() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -122,11 +99,8 @@ public class CyberArkVaultMultipleSecretsIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testMixedSecretTypes() throws Exception {
-        
context.getVaultConfiguration().cyberark().setUrl(System.getProperty("camel.cyberark.url"));
-        
context.getVaultConfiguration().cyberark().setAccount(System.getProperty("camel.cyberark.account"));
-        
context.getVaultConfiguration().cyberark().setUsername(System.getProperty("camel.cyberark.username"));
-        
context.getVaultConfiguration().cyberark().setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testMixedSecretTypes() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -151,11 +125,8 @@ public class CyberArkVaultMultipleSecretsIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testConnectionStringConstruction() throws Exception {
-        
context.getVaultConfiguration().cyberark().setUrl(System.getProperty("camel.cyberark.url"));
-        
context.getVaultConfiguration().cyberark().setAccount(System.getProperty("camel.cyberark.account"));
-        
context.getVaultConfiguration().cyberark().setUsername(System.getProperty("camel.cyberark.username"));
-        
context.getVaultConfiguration().cyberark().setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testConnectionStringConstruction() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
diff --git 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultProducerIT.java
 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultProducerIT.java
index 440167c20c6b..bc747cc145fc 100644
--- 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultProducerIT.java
+++ 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultProducerIT.java
@@ -21,31 +21,14 @@ import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.cyberark.vault.CyberArkVaultConstants;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperties;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
 
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
 
-// Must be manually tested. Provide CyberArk Conjur connection details using 
system properties:
-// -Dcamel.cyberark.url=http://localhost:8080
-// -Dcamel.cyberark.account=myConjurAccount
-// -Dcamel.cyberark.username=admin
-// -Dcamel.cyberark.apiKey=your-api-key
-@EnabledIfSystemProperties({
-        @EnabledIfSystemProperty(named = "camel.cyberark.url", matches = ".*",
-                                 disabledReason = "CyberArk Conjur URL not 
provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.account", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur account not 
provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.username", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur username 
not provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.apiKey", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur API key not 
provided")
-})
-public class CyberArkVaultProducerIT extends CyberArkTestSupport {
+class CyberArkVaultProducerIT extends CyberArkTestSupport {
 
     @BeforeAll
-    public static void setupSecrets() throws Exception {
+    static void setupSecrets() throws Exception {
 
         // Declare variables
         loadPolicy("""
@@ -112,10 +95,10 @@ public class CyberArkVaultProducerIT extends 
CyberArkTestSupport {
         return new RouteBuilder() {
             @Override
             public void configure() {
-                String url = System.getProperty("camel.cyberark.url");
-                String account = System.getProperty("camel.cyberark.account");
-                String username = 
System.getProperty("camel.cyberark.username");
-                String apiKey = System.getProperty("camel.cyberark.apiKey");
+                String url = service.url();
+                String account = service.account();
+                String username = service.username();
+                String apiKey = service.apiKey();
 
                 from("direct:getSecret")
                         
.toF("cyberark-vault:secret?secretId=test/secret&url=%s&account=%s&username=%s&apiKey=%s",
diff --git 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultPropertiesSourceIT.java
 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultPropertiesSourceIT.java
index ebde130085ff..0f8c5ae30908 100644
--- 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultPropertiesSourceIT.java
+++ 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/CyberArkVaultPropertiesSourceIT.java
@@ -19,33 +19,15 @@ package 
org.apache.camel.component.cyberark.vault.integration;
 import org.apache.camel.FailedToCreateRouteException;
 import org.apache.camel.builder.RouteBuilder;
 import org.apache.camel.component.mock.MockEndpoint;
-import org.apache.camel.vault.CyberArkVaultConfiguration;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperties;
-import org.junit.jupiter.api.condition.EnabledIfSystemProperty;
 
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-// Must be manually tested. Provide CyberArk Conjur connection details using 
system properties:
-// -Dcamel.cyberark.url=http://localhost:8080
-// -Dcamel.cyberark.account=myConjurAccount
-// -Dcamel.cyberark.username=admin
-// -Dcamel.cyberark.apiKey=your-api-key
-@EnabledIfSystemProperties({
-        @EnabledIfSystemProperty(named = "camel.cyberark.url", matches = ".*",
-                                 disabledReason = "CyberArk Conjur URL not 
provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.account", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur account not 
provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.username", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur username 
not provided"),
-        @EnabledIfSystemProperty(named = "camel.cyberark.apiKey", matches = 
".*",
-                                 disabledReason = "CyberArk Conjur API key not 
provided")
-})
-public class CyberArkVaultPropertiesSourceIT extends CyberArkTestSupport {
+class CyberArkVaultPropertiesSourceIT extends CyberArkTestSupport {
 
     @BeforeAll
-    public static void init() throws Exception {
+    static void init() throws Exception {
 
         // Declare variables
         loadPolicy("""
@@ -61,12 +43,8 @@ public class CyberArkVaultPropertiesSourceIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testSimpleSecretRetrieval() throws Exception {
-        CyberArkVaultConfiguration cyberark = 
context.getVaultConfiguration().cyberark();
-        cyberark.setUrl(System.getProperty("camel.cyberark.url"));
-        cyberark.setAccount(System.getProperty("camel.cyberark.account"));
-        cyberark.setUsername(System.getProperty("camel.cyberark.username"));
-        cyberark.setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testSimpleSecretRetrieval() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -84,12 +62,8 @@ public class CyberArkVaultPropertiesSourceIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testJsonFieldExtraction() throws Exception {
-        CyberArkVaultConfiguration cyberark = 
context.getVaultConfiguration().cyberark();
-        cyberark.setUrl(System.getProperty("camel.cyberark.url"));
-        cyberark.setAccount(System.getProperty("camel.cyberark.account"));
-        cyberark.setUsername(System.getProperty("camel.cyberark.username"));
-        cyberark.setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testJsonFieldExtraction() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -111,12 +85,8 @@ public class CyberArkVaultPropertiesSourceIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testDefaultValue() throws Exception {
-        CyberArkVaultConfiguration cyberark = 
context.getVaultConfiguration().cyberark();
-        cyberark.setUrl(System.getProperty("camel.cyberark.url"));
-        cyberark.setAccount(System.getProperty("camel.cyberark.account"));
-        cyberark.setUsername(System.getProperty("camel.cyberark.username"));
-        cyberark.setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testDefaultValue() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -134,12 +104,8 @@ public class CyberArkVaultPropertiesSourceIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testFieldWithDefaultValue() throws Exception {
-        CyberArkVaultConfiguration cyberark = 
context.getVaultConfiguration().cyberark();
-        cyberark.setUrl(System.getProperty("camel.cyberark.url"));
-        cyberark.setAccount(System.getProperty("camel.cyberark.account"));
-        cyberark.setUsername(System.getProperty("camel.cyberark.username"));
-        cyberark.setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testFieldWithDefaultValue() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -157,12 +123,9 @@ public class CyberArkVaultPropertiesSourceIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testSecretNotFound() {
+    void testSecretNotFound() {
         assertThrows(FailedToCreateRouteException.class, () -> {
-            
context.getVaultConfiguration().cyberark().setUrl(System.getProperty("camel.cyberark.url"));
-            
context.getVaultConfiguration().cyberark().setAccount(System.getProperty("camel.cyberark.account"));
-            
context.getVaultConfiguration().cyberark().setUsername(System.getProperty("camel.cyberark.username"));
-            
context.getVaultConfiguration().cyberark().setApiKey(System.getProperty("camel.cyberark.apiKey"));
+            configureVault();
 
             context.addRoutes(new RouteBuilder() {
                 @Override
@@ -179,11 +142,8 @@ public class CyberArkVaultPropertiesSourceIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testMultipleSecretsWithFields() throws Exception {
-        
context.getVaultConfiguration().cyberark().setUrl(System.getProperty("camel.cyberark.url"));
-        
context.getVaultConfiguration().cyberark().setAccount(System.getProperty("camel.cyberark.account"));
-        
context.getVaultConfiguration().cyberark().setUsername(System.getProperty("camel.cyberark.username"));
-        
context.getVaultConfiguration().cyberark().setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testMultipleSecretsWithFields() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
@@ -205,11 +165,8 @@ public class CyberArkVaultPropertiesSourceIT extends 
CyberArkTestSupport {
     }
 
     @Test
-    public void testComplexSecretPath() throws Exception {
-        
context.getVaultConfiguration().cyberark().setUrl(System.getProperty("camel.cyberark.url"));
-        
context.getVaultConfiguration().cyberark().setAccount(System.getProperty("camel.cyberark.account"));
-        
context.getVaultConfiguration().cyberark().setUsername(System.getProperty("camel.cyberark.username"));
-        
context.getVaultConfiguration().cyberark().setApiKey(System.getProperty("camel.cyberark.apiKey"));
+    void testComplexSecretPath() throws Exception {
+        configureVault();
 
         context.addRoutes(new RouteBuilder() {
             @Override
diff --git 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/README.md
 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/README.md
index cc21a3a0c770..2ca7a7685bdf 100644
--- 
a/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/README.md
+++ 
b/components/camel-cyberark-vault/src/test/java/org/apache/camel/component/cyberark/vault/integration/README.md
@@ -4,10 +4,28 @@ This directory contains integration tests for the Camel 
CyberArk Vault component
 
 ## Overview
 
-The integration tests require a running CyberArk Conjur instance and use 
system properties for configuration. Tests are disabled by default and only run 
when the required system properties are provided via command line.
+The tests run against a real CyberArk Conjur instance started automatically by
+`camel-test-infra-cyberark-vault`. No manual setup and no system properties 
are required - a
+working container runtime (Docker or Podman) is the only prerequisite.
+
+Conjur cannot run standalone, so the test infra starts **two** containers 
wired together on a
+private network:
+
+- `mirror.gcr.io/cyberark/conjur` - the Conjur server
+- `mirror.gcr.io/postgres` - the database Conjur stores its data in
+
+On startup the infra also creates the Conjur account and captures the 
generated admin API key,
+which is what the tests authenticate with.
+
+> **Architecture note:** the `cyberark/conjur` image is only published for 
`amd64` and `arm64`.
+> The ITs are therefore disabled on `ppc64le` and `s390x` via the 
`skipITs.ppc64le` and
+> `skipITs.s390x` properties in the component `pom.xml`.
 
 ## Test Classes
 
+All test classes extend `CyberArkTestSupport`, which registers the test infra 
service and exposes
+the `loadPolicy`, `createSecret` and `configureVault` helpers.
+
 ### CyberArkVaultPropertiesSourceIT
 Tests for the properties function (`{{cyberark:...}}`):
 - Simple secret retrieval
@@ -21,7 +39,6 @@ Tests for the component endpoint 
(`cyberark-vault://secretId`):
 - Basic secret retrieval via component endpoint
 - Dynamic secret ID via headers
 - Header verification (SECRET_ID, SECRET_VALUE constants)
-- Multiple secret retrieval
 
 ### CyberArkVaultMultipleSecretsIT
 Tests for complex scenarios with multiple secrets:
@@ -32,385 +49,90 @@ Tests for complex scenarios with multiple secrets:
 
 ## Running the Tests
 
-### Prerequisites
-
-- A running CyberArk Conjur instance (see Setup section below)
-- Maven 3.6+
-- Java 11+
-- CyberArk Conjur admin credentials
-
-### Required System Properties
-
-The tests require the following system properties:
-
-- `camel.cyberark.url` - CyberArk Conjur URL (e.g., `http://localhost:8080`)
-- `camel.cyberark.account` - Conjur account name (e.g., `myConjurAccount`)
-- `camel.cyberark.username` - Admin username (e.g., `admin`)
-- `camel.cyberark.apiKey` - Admin API key
-
-### Run All Integration Tests
-
 ```bash
 cd components/camel-cyberark-vault
-mvn clean verify \
-  -Dcamel.cyberark.url=http://localhost:8080 \
-  -Dcamel.cyberark.account=myConjurAccount \
-  -Dcamel.cyberark.username=admin \
-  -Dcamel.cyberark.apiKey=your-api-key
-```
-
-### Run Specific Test Class
 
-```bash
-mvn clean verify -Dit.test=CyberArkVaultPropertiesSourceIT \
-  -Dcamel.cyberark.url=http://localhost:8080 \
-  -Dcamel.cyberark.account=myConjurAccount \
-  -Dcamel.cyberark.username=admin \
-  -Dcamel.cyberark.apiKey=your-api-key
-```
+# all integration tests
+mvn clean verify
 
-### Run Specific Test Method
+# a single test class
+mvn clean verify -Dit.test=CyberArkVaultPropertiesSourceIT
 
-```bash
-mvn clean verify 
-Dit.test=CyberArkVaultPropertiesSourceIT#testSimpleSecretRetrieval \
-  -Dcamel.cyberark.url=http://localhost:8080 \
-  -Dcamel.cyberark.account=myConjurAccount \
-  -Dcamel.cyberark.username=admin \
-  -Dcamel.cyberark.apiKey=your-api-key
+# a single test method
+mvn clean verify 
-Dit.test=CyberArkVaultPropertiesSourceIT#testSimpleSecretRetrieval
 ```
 
-### Skip Integration Tests (Default)
-
-By default, integration tests are skipped if system properties are not 
provided:
-
-```bash
-mvn clean install
-```
-
-## Setting Up CyberArk Conjur for Testing
-
-### Option 1: Using Docker (Recommended)
-
-Use the official CyberArk Conjur quickstart setup:
-
-```bash
-# Clone the quickstart repository
-git clone https://github.com/cyberark/conjur-quickstart.git
-cd conjur-quickstart
-
-# Generate the master key 
-docker compose run --no-deps --rm conjur data-key generate > data_key
-
-# Load master key as an environment variable
-export CONJUR_DATA_KEY="$(< data_key)"
-
-# Start Conjur and database
-docker compose up -d
-
-# Create an admin account (in another terminal)
-docker compose exec conjur conjurctl account create myConjurAccount > 
admin_data
-
-# The admin API key will be in the admin_data file
-cat admin_data | grep "API key"
-```
-
-Default connection details:
-- **URL**: `http://localhost:8080`
-- **Account**: `myConjurAccount`
-- **Username**: `admin`
-- **API Key**: See admin_data
-
-### Option 2: Using Existing Conjur Instance
+## Declaring Secrets
 
-If you have an existing CyberArk Conjur instance:
+A Conjur secret is two distinct things:
 
-1. Ensure you have admin access
-2. Get your admin API key
-3. Use your instance URL and account name
+1. a `variable` resource **declared by a policy**, and
+2. a value assigned to that variable through the Secrets API.
 
-## Test Infrastructure
-
-### Authentication
-
-The tests authenticate using the provided credentials before running:
+The Secrets API can only update the value - it cannot create the variable. 
Setting a value for a
+variable that was never declared returns `404 Variable not found`, so every 
test must load a
+policy before creating its secrets:
 
 ```java
 @BeforeAll
-public static void init() throws Exception {
-    // Authenticate and get token
-    authToken = authenticate();
-
-    // Create test secrets
+static void init() throws Exception {
+    // 1. declare the variables
+    loadPolicy("""
+            - !variable simple-secret
+            - !variable database
+            """);
+
+    // 2. then assign their values
     createSecret("simple-secret", "my-simple-value");
     createSecret("database", 
"{\"username\":\"dbuser\",\"password\":\"dbpass\"}");
 }
 ```
 
-### Creating Test Secrets
-
-The tests create secrets using the Conjur REST API:
+## Adding New Tests
 
 ```java
-private static void createSecret(String secretId, String secretValue) {
-    String url = String.format("%s/secrets/%s/variable/%s",
-            System.getProperty("camel.cyberark.url"),
-            System.getProperty("camel.cyberark.account"),
-            secretId);
-
-    HttpRequest request = HttpRequest.newBuilder()
-            .uri(URI.create(url))
-            .header("Authorization", "Token token=\"" + encodedToken + "\"")
-            .POST(HttpRequest.BodyPublishers.ofString(secretValue))
-            .build();
-
-    httpClient.send(request, HttpResponse.BodyHandlers.ofString());
-}
-```
-
-## Test Scenarios Covered
-
-### Properties Function Tests
-
-1. **Simple Secret Retrieval**
-   ```java
-   {{cyberark:simple-secret}} → "my-simple-value"
-   ```
-
-2. **JSON Field Extraction**
-   ```java
-   {{cyberark:database#username}} → "dbuser"
-   {{cyberark:database#password}} → "dbpass"
-   ```
-
-3. **Default Values**
-   ```java
-   {{cyberark:nonexistent:defaultValue}} → "defaultValue"
-   {{cyberark:database#missing:defaultUser}} → "defaultUser"
-   ```
-
-4. **Complex Paths**
-   ```java
-   {{cyberark:api/credentials#token}} → "secret-token"
-   ```
-
-5. **Error Handling**
-   ```java
-   {{cyberark:nonexistent}} → FailedToCreateRouteException
-   ```
-
-### Component Endpoint Tests
-
-1. **Basic Retrieval**
-   ```java
-   from("direct:start")
-       .to("cyberark-vault:test/secret?url=...&account=...&apiKey=...")
-       .to("mock:result");
-   ```
-
-2. **Dynamic Secret ID**
-   ```java
-   exchange.getMessage().setHeader(CyberArkVaultConstants.SECRET_ID, 
"production/database");
-   ```
+class MyNewIT extends CyberArkTestSupport {
 
-3. **Header Verification**
-   - `CyberArkVaultConstants.SECRET_ID`
-   - `CyberArkVaultConstants.SECRET_VALUE`
-
-## Troubleshooting
-
-### Tests are Skipped
-
-If you see messages like `CyberArk Conjur URL not provided`, ensure you're 
passing all required system properties:
-
-```bash
-mvn verify \
-  -Dcamel.cyberark.url=http://localhost:8080 \
-  -Dcamel.cyberark.account=myConjurAccount \
-  -Dcamel.cyberark.username=admin \
-  -Dcamel.cyberark.apiKey=your-api-key
-```
-
-### Authentication Failures
-
-If authentication fails:
-- Verify the URL is accessible
-- Check that the account name is correct
-- Verify the username and API key are valid
-- Ensure Conjur is fully started and accepting connections
-
-### Connection Refused
-
-If you get connection refused errors:
-- Check that Conjur is running: `docker ps | grep conjur`
-- Verify the URL and port are correct
-- Check firewall settings if using remote instance
-
-### Secret Creation Failures
-
-The tests automatically create secrets they need. If secret creation fails:
-- Ensure the API key has permission to create secrets
-- Check Conjur logs for policy-related errors
-- Verify the account name is correct
-
-## CI/CD Integration
-
-### GitHub Actions Example
-
-```yaml
-name: Integration Tests
-on: [push, pull_request]
-
-jobs:
-  test:
-    runs-on: ubuntu-latest
-
-    services:
-      postgres:
-        image: postgres:15
-        env:
-          POSTGRES_PASSWORD: SuperSecretPg
-        ports:
-          - 5432:5432
-
-      conjur:
-        image: cyberark/conjur
-        env:
-          DATABASE_URL: postgres://postgres:SuperSecretPg@postgres/postgres
-          CONJUR_DATA_KEY: W0BuL24xJMVfGNTKRxcC4xv76cKE7wNJh0AKXdvmnxk=
-        ports:
-          - 8080:80
-
-    steps:
-      - uses: actions/checkout@v2
-
-      - name: Set up JDK 11
-        uses: actions/setup-java@v2
-        with:
-          java-version: '11'
-
-      - name: Initialize Conjur Account
-        run: |
-          # Wait for Conjur to start
-          sleep 10
-          # Create account and extract API key
-          API_KEY=$(docker exec conjur conjurctl account create 
myConjurAccount | grep "API key" | awk '{print $NF}')
-          echo "CONJUR_API_KEY=$API_KEY" >> $GITHUB_ENV
-
-      - name: Run Integration Tests
-        run: |
-          mvn clean verify \
-            -Dcamel.cyberark.url=http://localhost:8080 \
-            -Dcamel.cyberark.account=myConjurAccount \
-            -Dcamel.cyberark.username=admin \
-            -Dcamel.cyberark.apiKey=${{ env.CONJUR_API_KEY }}
-```
-
-### Jenkins Example
-
-```groovy
-pipeline {
-    agent any
-
-    stages {
-        stage('Setup Conjur') {
-            steps {
-                sh '''
-                    docker-compose -f test-resources/conjur-docker-compose.yml 
up -d
-                    sleep 10
-                '''
-            }
-        }
-
-        stage('Run Integration Tests') {
-            steps {
-                sh '''
-                    API_KEY=$(docker exec conjur conjurctl account create 
myConjurAccount | grep "API key" | awk '{print $NF}')
-                    mvn clean verify \
-                        -Dcamel.cyberark.url=http://localhost:8080 \
-                        -Dcamel.cyberark.account=myConjurAccount \
-                        -Dcamel.cyberark.username=admin \
-                        -Dcamel.cyberark.apiKey=$API_KEY
-                '''
-            }
-        }
+    @BeforeAll
+    static void setup() throws Exception {
+        loadPolicy("- !variable my/secret");
+        createSecret("my/secret", "value");
     }
 
-    post {
-        always {
-            sh 'docker-compose -f test-resources/conjur-docker-compose.yml 
down'
-        }
+    @Test
+    void testSomething() throws Exception {
+        // for the properties function, point the vault configuration at the 
test infra
+        configureVault();
+        ...
     }
 }
 ```
 
-## Test Data
+Use unique secret IDs per test class to avoid clashes, since the Conjur 
instance is shared across
+the test classes running in the same JVM.
+
+When the component endpoint is used directly, the connection details come from 
the service:
+
+```java
+service.url()       // e.g. http://localhost:32768
+service.account()   // myConjurAccount
+service.username()  // admin
+service.apiKey()    // generated on startup
+```
 
-### Created Secrets
+## Troubleshooting
 
-The integration tests create the following secrets:
+### Tests fail to start the containers
 
-| Secret ID | Value | Purpose |
-|-----------|-------|---------|
-| `simple-secret` | `my-simple-value` | Basic retrieval test |
-| `database` | `{"username":"dbuser",...}` | JSON field extraction |
-| `api/credentials` | `{"token":"secret-token",...}` | Complex path test |
-| `test/secret` | `mySecretValue` | Component endpoint test |
-| `production/database` | `{"username":"prod-user",...}` | Dynamic retrieval 
test |
-| `app/config` | `{"port":"8080",...}` | Multiple secrets test |
-| `db/primary` | `{"host":"db1.example.com",...}` | Multiple configs test |
-| `db/replica` | `{"host":"db2.example.com",...}` | Multiple configs test |
-| `cache/redis` | `{"host":"redis.example.com",...}` | Mixed types test |
+- Verify the container runtime is running and reachable by Testcontainers
+- The first run pulls both images, which can take a while on a slow connection
 
-## Adding New Tests
+### Secret creation fails with 404
 
-To add new integration tests:
-
-1. **Create Test Class**:
-   ```java
-   @EnabledIfSystemProperties({
-       @EnabledIfSystemProperty(named = "camel.cyberark.url", matches = ".*",
-                                disabledReason = "CyberArk Conjur URL not 
provided"),
-       @EnabledIfSystemProperty(named = "camel.cyberark.account", matches = 
".*",
-                                disabledReason = "CyberArk Conjur account not 
provided"),
-       @EnabledIfSystemProperty(named = "camel.cyberark.username", matches = 
".*",
-                                disabledReason = "CyberArk Conjur username not 
provided"),
-       @EnabledIfSystemProperty(named = "camel.cyberark.apiKey", matches = 
".*",
-                                disabledReason = "CyberArk Conjur API key not 
provided")
-   })
-   public class MyNewIT extends CamelTestSupport {
-       // Tests here
-   }
-   ```
-
-2. **Create Secrets in @BeforeAll**:
-   ```java
-   @BeforeAll
-   public static void setup() throws Exception {
-       authToken = authenticate();
-       createSecret("my/secret", "value");
-   }
-   ```
-
-3. **Use System Properties for Connection**:
-   ```java
-   String url = System.getProperty("camel.cyberark.url");
-   String account = System.getProperty("camel.cyberark.account");
-   String username = System.getProperty("camel.cyberark.username");
-   String apiKey = System.getProperty("camel.cyberark.apiKey");
-   ```
-
-## Best Practices
-
-1. **Cleanup**: Secrets can be cleaned up manually or will be reset when 
Conjur restarts
-2. **Isolation**: Use unique secret IDs for each test to avoid conflicts
-3. **Logging**: Use SLF4J logger to debug issues
-4. **Assertions**: Use MockEndpoint.assertIsSatisfied() for async verification
-5. **Error Testing**: Use assertThrows() for expected failures
-6. **System Properties**: Always use System.getProperty() to read configuration
+The variable was not declared - add it to the `loadPolicy` call as described 
above.
 
 ## References
 
-- [CyberArk Conjur 
Documentation](https://docs.cyberark.com/Product-Doc/OnlineHelp/AAM-DAP/Latest/en/Content/Resources/_TopNav/cc_Home.htm)
-- [CyberArk Conjur Quickstart](https://github.com/cyberark/conjur-quickstart)
+- [CyberArk Conjur 
Documentation](https://docs.cyberark.com/conjur-open-source/latest/en/content/resources/_topnav/cc_home.htm)
+- [Conjur Policy 
Reference](https://docs.cyberark.com/conjur-open-source/latest/en/content/operations/policy/policy-syntax.htm)
 - [Camel Testing Guide](https://camel.apache.org/manual/testing.html)
-- [JUnit 5 Conditional Test 
Execution](https://junit.org/junit5/docs/current/user-guide/#writing-tests-conditional-execution)
diff --git a/test-infra/camel-test-infra-all/pom.xml 
b/test-infra/camel-test-infra-all/pom.xml
index e79e00a3a525..104e54ee351c 100644
--- a/test-infra/camel-test-infra-all/pom.xml
+++ b/test-infra/camel-test-infra-all/pom.xml
@@ -196,6 +196,11 @@
             <artifactId>camel-test-infra-openldap</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-cyberark-vault</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>org.apache.camel</groupId>
             <artifactId>camel-test-infra-hashicorp-vault</artifactId>
@@ -515,6 +520,12 @@
                                         
<artifactId>camel-test-infra-openldap</artifactId>
                                     </dependency>
                                 </fileSet>
+                                <fileSet>
+                                    <dependency>
+                                        <groupId>org.apache.camel</groupId>
+                                        
<artifactId>camel-test-infra-cyberark-vault</artifactId>
+                                    </dependency>
+                                </fileSet>
                                 <fileSet>
                                     <dependency>
                                         <groupId>org.apache.camel</groupId>
diff --git 
a/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
 
b/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
index a1b236ed29ce..c73de002b73d 100644
--- 
a/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
+++ 
b/test-infra/camel-test-infra-all/src/generated/resources/META-INF/metadata.json
@@ -339,6 +339,17 @@
   "version" : "4.22.0-SNAPSHOT",
   "serviceVersion" : "0.3",
   "uiSupported" : false
+}, {
+  "service" : 
"org.apache.camel.test.infra.cyberark.vault.services.CyberArkVaultInfraService",
+  "description" : "CyberArk Conjur is an open source secrets management 
solution",
+  "implementation" : 
"org.apache.camel.test.infra.cyberark.vault.services.CyberArkVaultLocalContainerInfraService",
+  "alias" : [ "cyberark" ],
+  "aliasImplementation" : [ "conjur" ],
+  "groupId" : "org.apache.camel",
+  "artifactId" : "camel-test-infra-cyberark-vault",
+  "version" : "4.22.0-SNAPSHOT",
+  "serviceVersion" : "1.24.0",
+  "uiSupported" : false
 }, {
   "service" : 
"org.apache.camel.test.infra.opensearch.services.OpenSearchInfraService",
   "description" : "OpenSearch is a distributed search and analytics engine",
diff --git a/test-infra/camel-test-infra-cyberark-vault/pom.xml 
b/test-infra/camel-test-infra-cyberark-vault/pom.xml
new file mode 100644
index 000000000000..77453ecb1d6a
--- /dev/null
+++ b/test-infra/camel-test-infra-cyberark-vault/pom.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    Licensed to the Apache Software Foundation (ASF) under one or more
+    contributor license agreements.  See the NOTICE file distributed with
+    this work for additional information regarding copyright ownership.
+    The ASF licenses this file to You under the Apache License, Version 2.0
+    (the "License"); you may not use this file except in compliance with
+    the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <parent>
+        <artifactId>camel-test-infra-parent</artifactId>
+        <groupId>org.apache.camel</groupId>
+        <relativePath>../camel-test-infra-parent/pom.xml</relativePath>
+        <version>4.22.0-SNAPSHOT</version>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>camel-test-infra-cyberark-vault</artifactId>
+    <name>Camel :: Test Infra :: CyberArk Vault</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.camel</groupId>
+            <artifactId>camel-test-infra-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.awaitility</groupId>
+            <artifactId>awaitility</artifactId>
+            <version>${awaitility-version}</version>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git 
a/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/common/CyberArkVaultProperties.java
 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/common/CyberArkVaultProperties.java
new file mode 100644
index 000000000000..b39994093cee
--- /dev/null
+++ 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/common/CyberArkVaultProperties.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.camel.test.infra.cyberark.vault.common;
+
+public final class CyberArkVaultProperties {
+    public static final String CYBERARK_VAULT_CONTAINER = 
"cyberark.conjur.container";
+    public static final String CYBERARK_VAULT_POSTGRES_CONTAINER = 
"cyberark.conjur.database.container";
+    public static final String CYBERARK_VAULT_URL = "cyberark.vault.url";
+    public static final String CYBERARK_VAULT_HOST = "cyberark.vault.host";
+    public static final String CYBERARK_VAULT_PORT = "cyberark.vault.port";
+    public static final String CYBERARK_VAULT_ACCOUNT = 
"cyberark.vault.account";
+    public static final String CYBERARK_VAULT_USERNAME = 
"cyberark.vault.username";
+    public static final String CYBERARK_VAULT_API_KEY = 
"cyberark.vault.api.key";
+    public static final int DEFAULT_SERVICE_PORT = 80;
+
+    private CyberArkVaultProperties() {
+
+    }
+}
diff --git 
a/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultInfraService.java
 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultInfraService.java
new file mode 100644
index 000000000000..ddde8ebac6d5
--- /dev/null
+++ 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultInfraService.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.test.infra.cyberark.vault.services;
+
+import org.apache.camel.test.infra.common.services.InfrastructureService;
+
+/**
+ * Test infra service for CyberArk Conjur Vault
+ */
+public interface CyberArkVaultInfraService extends InfrastructureService {
+
+    /**
+     * The Conjur account created on startup
+     */
+    String account();
+
+    /**
+     * The administrative user owning {@link #apiKey()}
+     */
+    String username();
+
+    /**
+     * The API key of {@link #username()}, generated by Conjur when the 
account is created
+     */
+    String apiKey();
+
+    int port();
+
+    String host();
+
+    default String scheme() {
+        return "http";
+    }
+
+    /**
+     * The base URL of the Conjur REST API
+     */
+    default String url() {
+        return String.format("%s://%s:%d", scheme(), host(), port());
+    }
+}
diff --git 
a/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultLocalContainerInfraService.java
 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultLocalContainerInfraService.java
new file mode 100644
index 000000000000..1740059434a0
--- /dev/null
+++ 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultLocalContainerInfraService.java
@@ -0,0 +1,247 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.test.infra.cyberark.vault.services;
+
+import java.io.IOException;
+import java.time.Duration;
+import java.util.Objects;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import org.apache.camel.spi.annotations.InfraService;
+import org.apache.camel.test.infra.common.LocalPropertyResolver;
+import org.apache.camel.test.infra.common.services.ContainerEnvironmentUtil;
+import org.apache.camel.test.infra.common.services.ContainerService;
+import 
org.apache.camel.test.infra.cyberark.vault.common.CyberArkVaultProperties;
+import org.awaitility.Awaitility;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.testcontainers.containers.Container;
+import org.testcontainers.containers.GenericContainer;
+import org.testcontainers.containers.Network;
+import org.testcontainers.containers.output.OutputFrame;
+import org.testcontainers.containers.output.Slf4jLogConsumer;
+import org.testcontainers.containers.wait.strategy.Wait;
+import org.testcontainers.utility.DockerImageName;
+
+/**
+ * A CyberArk Conjur Vault service backed by containers.
+ * <p>
+ * Unlike most other infra services this one starts <em>two</em> containers: 
Conjur cannot run standalone, it requires a
+ * PostgreSQL backend. Both are wired together on a private {@link Network}, 
and only Conjur is exposed to the host.
+ * <p>
+ * Conjur has no admin credentials until an account is created, so the API key 
is generated on startup by running
+ * {@code conjurctl account create} inside the container.
+ * <p>
+ * Note that Conjur listens on port 80 inside the container. Tests get a 
random host port; when running under
+ * {@code camel infra run} (fixed port mode) set {@code camel.infra.port} to 
avoid binding the privileged host port 80.
+ */
+@InfraService(service = CyberArkVaultInfraService.class,
+              description = "CyberArk Conjur is an open source secrets 
management solution",
+              serviceAlias = "cyberark",
+              serviceImplementationAlias = "conjur")
+public class CyberArkVaultLocalContainerInfraService
+        implements CyberArkVaultInfraService, 
ContainerService<GenericContainer<?>> {
+
+    public static final String CONTAINER_NAME = "cyberark-vault";
+
+    private static final Logger LOG = 
LoggerFactory.getLogger(CyberArkVaultLocalContainerInfraService.class);
+
+    private static final String DEFAULT_ACCOUNT = "myConjurAccount";
+    private static final String DEFAULT_USERNAME = "admin";
+    private static final String POSTGRES_NETWORK_ALIAS = "database";
+    private static final String POSTGRES_USER = "postgres";
+    private static final String POSTGRES_PASSWORD = "SuperSecret";
+    private static final String POSTGRES_DB = "postgres";
+
+    /**
+     * Fixed throwaway key used to encrypt the Conjur database. This is the 
key published in the Conjur quickstart
+     * documentation - it guards nothing but ephemeral test data.
+     */
+    private static final String DATA_KEY = 
"W0BuL24xJMVfGNTKRxcC4xv76cKE7wNJh0AKXdvmnxk=";
+
+    private static final Pattern API_KEY_PATTERN = Pattern.compile("API key 
for admin:\\s*(\\S+)");
+
+    private final Network network;
+    private final GenericContainer<?> postgresContainer;
+    private final GenericContainer<?> container;
+
+    private String apiKey;
+
+    public CyberArkVaultLocalContainerInfraService() {
+        this(LocalPropertyResolver.getProperty(
+                CyberArkVaultLocalContainerInfraService.class,
+                CyberArkVaultProperties.CYBERARK_VAULT_CONTAINER),
+             LocalPropertyResolver.getProperty(
+                     CyberArkVaultLocalContainerInfraService.class,
+                     
CyberArkVaultProperties.CYBERARK_VAULT_POSTGRES_CONTAINER));
+    }
+
+    public CyberArkVaultLocalContainerInfraService(String containerImage, 
String postgresContainerImage) {
+        network = Network.newNetwork();
+        postgresContainer = initPostgresContainer(postgresContainerImage);
+        container = initContainer(containerImage, CONTAINER_NAME);
+
+        String name = ContainerEnvironmentUtil.containerName(this.getClass());
+        if (name != null) {
+            container.withCreateContainerCmdModifier(cmd -> 
cmd.withName(name));
+        }
+    }
+
+    protected GenericContainer<?> initPostgresContainer(String imageName) {
+        GenericContainer<?> postgres = new 
GenericContainer<>(DockerImageName.parse(imageName));
+
+        postgres.withNetwork(network)
+                .withNetworkAliases(POSTGRES_NETWORK_ALIAS)
+                .withEnv("POSTGRES_USER", POSTGRES_USER)
+                .withEnv("POSTGRES_PASSWORD", POSTGRES_PASSWORD)
+                .withEnv("POSTGRES_DB", POSTGRES_DB)
+                // the message is logged once by the bootstrap server and once 
by the real one
+                .waitingFor(Wait.forLogMessage(".*database system is ready to 
accept connections.*", 2)
+                        .withStartupTimeout(Duration.ofMinutes(2)));
+
+        return postgres;
+    }
+
+    protected GenericContainer<?> initContainer(String imageName, String 
containerName) {
+        final Logger containerLog = LoggerFactory.getLogger("container." + 
containerName);
+        final Consumer<OutputFrame> logConsumer = new 
Slf4jLogConsumer(containerLog);
+
+        GenericContainer<?> conjur = new 
GenericContainer<>(DockerImageName.parse(imageName));
+
+        conjur.withNetwork(network)
+                .withNetworkAliases(containerName)
+                .withEnv("DATABASE_URL",
+                        String.format("postgres://%s:%s@%s/%s",
+                                POSTGRES_USER, POSTGRES_PASSWORD, 
POSTGRES_NETWORK_ALIAS, POSTGRES_DB))
+                .withEnv("CONJUR_DATA_KEY", DATA_KEY)
+                .withEnv("CONJUR_AUTHENTICATORS", "authn")
+                .withCommand("server")
+                .withLogConsumer(logConsumer)
+                .waitingFor(Wait.forLogMessage(".*Listening on http://.*";, 1)
+                        .withStartupTimeout(Duration.ofMinutes(3)));
+
+        ContainerEnvironmentUtil.configurePort(conjur,
+                ContainerEnvironmentUtil.isFixedPort(this.getClass()),
+                CyberArkVaultProperties.DEFAULT_SERVICE_PORT);
+
+        return conjur;
+    }
+
+    @Override
+    public void registerProperties() {
+        System.setProperty(CyberArkVaultProperties.CYBERARK_VAULT_HOST, 
host());
+        System.setProperty(CyberArkVaultProperties.CYBERARK_VAULT_PORT, 
String.valueOf(port()));
+        System.setProperty(CyberArkVaultProperties.CYBERARK_VAULT_URL, url());
+        System.setProperty(CyberArkVaultProperties.CYBERARK_VAULT_ACCOUNT, 
account());
+        System.setProperty(CyberArkVaultProperties.CYBERARK_VAULT_USERNAME, 
username());
+        System.setProperty(CyberArkVaultProperties.CYBERARK_VAULT_API_KEY, 
apiKey());
+    }
+
+    @Override
+    public void initialize() {
+        LOG.info("Trying to start the CyberArk Conjur database container");
+        postgresContainer.start();
+
+        LOG.info("Trying to start the CyberArk Conjur container");
+        container.withStartupAttempts(5);
+        container.start();
+
+        apiKey = createAdminAccount();
+
+        registerProperties();
+        LOG.info("CyberArk Conjur running at {} on account {}", url(), 
account());
+    }
+
+    @Override
+    public void shutdown() {
+        LOG.info("Stopping the CyberArk Conjur container");
+        container.stop();
+        postgresContainer.stop();
+
+        System.clearProperty(CyberArkVaultProperties.CYBERARK_VAULT_HOST);
+        System.clearProperty(CyberArkVaultProperties.CYBERARK_VAULT_PORT);
+        System.clearProperty(CyberArkVaultProperties.CYBERARK_VAULT_URL);
+        System.clearProperty(CyberArkVaultProperties.CYBERARK_VAULT_ACCOUNT);
+        System.clearProperty(CyberArkVaultProperties.CYBERARK_VAULT_USERNAME);
+        System.clearProperty(CyberArkVaultProperties.CYBERARK_VAULT_API_KEY);
+    }
+
+    /**
+     * Creates the Conjur account and returns the generated admin API key.
+     * <p>
+     * Conjur starts accepting connections slightly before it is able to serve 
them, so this is retried until it
+     * succeeds rather than run once.
+     */
+    private String createAdminAccount() {
+        return Awaitility.await()
+                .atMost(2, TimeUnit.MINUTES)
+                .pollDelay(Duration.ZERO)
+                .pollInterval(2, TimeUnit.SECONDS)
+                .ignoreExceptions()
+                .until(this::doCreateAdminAccount, Objects::nonNull);
+    }
+
+    private String doCreateAdminAccount() throws IOException, 
InterruptedException {
+        Container.ExecResult result
+                = container.execInContainer("conjurctl", "account", "create", 
DEFAULT_ACCOUNT);
+
+        Matcher matcher = API_KEY_PATTERN.matcher(result.getStdout());
+        if (matcher.find()) {
+            return matcher.group(1);
+        }
+
+        // The account outlives a container restart, in which case creating it 
fails and the
+        // already generated key has to be retrieved instead
+        result = container.execInContainer("conjurctl", "role", 
"retrieve-key", DEFAULT_ACCOUNT + ":user:admin");
+        String key = result.getStdout().trim();
+
+        return key.isEmpty() ? null : key;
+    }
+
+    @Override
+    public GenericContainer<?> getContainer() {
+        return container;
+    }
+
+    @Override
+    public String account() {
+        return DEFAULT_ACCOUNT;
+    }
+
+    @Override
+    public String username() {
+        return DEFAULT_USERNAME;
+    }
+
+    @Override
+    public String apiKey() {
+        return apiKey;
+    }
+
+    @Override
+    public int port() {
+        return 
container.getMappedPort(CyberArkVaultProperties.DEFAULT_SERVICE_PORT);
+    }
+
+    @Override
+    public String host() {
+        return container.getHost();
+    }
+}
diff --git 
a/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultService.java
 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultService.java
new file mode 100644
index 000000000000..14f6c9bfb4b4
--- /dev/null
+++ 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultService.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.test.infra.cyberark.vault.services;
+
+import org.apache.camel.test.infra.common.services.ContainerTestService;
+import org.apache.camel.test.infra.common.services.TestService;
+
+/**
+ * Test infra service for CyberArk Conjur Vault
+ */
+public interface CyberArkVaultService extends TestService, 
CyberArkVaultInfraService, ContainerTestService {
+}
diff --git 
a/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultServiceFactory.java
 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultServiceFactory.java
new file mode 100644
index 000000000000..a9395684d188
--- /dev/null
+++ 
b/test-infra/camel-test-infra-cyberark-vault/src/main/java/org/apache/camel/test/infra/cyberark/vault/services/CyberArkVaultServiceFactory.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.test.infra.cyberark.vault.services;
+
+import org.apache.camel.test.infra.common.services.SimpleTestServiceBuilder;
+
+public final class CyberArkVaultServiceFactory {
+    private CyberArkVaultServiceFactory() {
+
+    }
+
+    public static SimpleTestServiceBuilder<CyberArkVaultService> builder() {
+        return new SimpleTestServiceBuilder<>("cyberark-vault");
+    }
+
+    public static CyberArkVaultService createService() {
+        return builder()
+                .addLocalMapping(CyberArkVaultLocalContainerService::new)
+                .build();
+    }
+
+    public static class CyberArkVaultLocalContainerService extends 
CyberArkVaultLocalContainerInfraService
+            implements CyberArkVaultService {
+    }
+}
diff --git 
a/test-infra/camel-test-infra-cyberark-vault/src/main/resources/META-INF/MANIFEST.MF
 
b/test-infra/camel-test-infra-cyberark-vault/src/main/resources/META-INF/MANIFEST.MF
new file mode 100644
index 000000000000..e69de29bb2d1
diff --git 
a/test-infra/camel-test-infra-cyberark-vault/src/main/resources/org/apache/camel/test/infra/cyberark/vault/services/container.properties
 
b/test-infra/camel-test-infra-cyberark-vault/src/main/resources/org/apache/camel/test/infra/cyberark/vault/services/container.properties
new file mode 100644
index 000000000000..40d26ad54eef
--- /dev/null
+++ 
b/test-infra/camel-test-infra-cyberark-vault/src/main/resources/org/apache/camel/test/infra/cyberark/vault/services/container.properties
@@ -0,0 +1,24 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+## The key prefixes must stay unique across all test-infra modules: the 
metadata generator merges
+## every container.properties into a single map and matches keys by service 
alias suffix
+cyberark.conjur.container=mirror.gcr.io/cyberark/conjur:1.24.0
+cyberark.conjur.container.version.exclude=rc,beta,alpha
+## Conjur cannot run standalone: it requires a PostgreSQL backend
+cyberark.conjur.database.container=mirror.gcr.io/postgres:17.10-alpine
+cyberark.conjur.database.container.version.include=alpine
+cyberark.conjur.database.container.version.freeze.major=true
diff --git a/test-infra/pom.xml b/test-infra/pom.xml
index 9d71d087c2a1..44c862d2f94a 100644
--- a/test-infra/pom.xml
+++ b/test-infra/pom.xml
@@ -82,6 +82,7 @@
         <module>camel-test-infra-openldap</module>
         <module>camel-test-infra-ignite</module>
         <module>camel-test-infra-hashicorp-vault</module>
+        <module>camel-test-infra-cyberark-vault</module>
         <module>camel-test-infra-jetty</module>
         <module>camel-test-infra-keycloak</module>
         <module>camel-test-infra-core</module>

Reply via email to