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>