From edc309d9400590408034fe6aef383e160d48351c Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Wed, 2 Dec 2020 16:40:23 +0200 Subject: [PATCH 1/6] Feature flag to register the new encrypted repository type --- .../encrypted/EncryptedRepositoryPlugin.java | 156 ++++++++++-------- 1 file changed, 91 insertions(+), 65 deletions(-) diff --git a/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java b/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java index 849914fa72495..2400325632a04 100644 --- a/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java +++ b/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java @@ -9,6 +9,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.message.ParameterizedMessage; +import org.elasticsearch.Build; import org.elasticsearch.cluster.metadata.RepositoryMetadata; import org.elasticsearch.cluster.service.ClusterService; import org.elasticsearch.common.Strings; @@ -37,6 +38,26 @@ import java.util.function.Supplier; public class EncryptedRepositoryPlugin extends Plugin implements RepositoryPlugin { + + private static final Boolean ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED; + static { + final String property = System.getProperty("es.encrypted_repository_feature_flag_registered"); + if (Build.CURRENT.isSnapshot() && property != null) { + throw new IllegalArgumentException("es.encrypted_repository_feature_flag_registered is only supported in non-snapshot builds"); + } + if ("true".equals(property)) { + ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED = true; + } else if ("false".equals(property)) { + ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED = false; + } else if (property == null) { + ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED = null; + } else { + throw new IllegalArgumentException( + "expected es.encrypted_repository_feature_flag_registered to be unset or [true|false] but was [" + property + "]" + ); + } + } + static final Logger logger = LogManager.getLogger(EncryptedRepositoryPlugin.class); static final String REPOSITORY_TYPE_NAME = "encrypted"; // TODO add at least hdfs, and investigate supporting all `BlobStoreRepository` implementations @@ -76,76 +97,81 @@ public Map getRepositories( } final Map repositoryPasswordsMap = Map.copyOf(repositoryPasswordsMapBuilder); - return Collections.singletonMap(REPOSITORY_TYPE_NAME, new Repository.Factory() { - - @Override - public Repository create(RepositoryMetadata metadata) { - throw new UnsupportedOperationException(); - } + if (Build.CURRENT.isSnapshot() || (ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED != null && + ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED)) { + return Collections.singletonMap(REPOSITORY_TYPE_NAME, new Repository.Factory() { - @Override - public Repository create(RepositoryMetadata metadata, Function typeLookup) throws Exception { - final String delegateType = DELEGATE_TYPE_SETTING.get(metadata.settings()); - if (Strings.hasLength(delegateType) == false) { - throw new IllegalArgumentException("Repository setting [" + DELEGATE_TYPE_SETTING.getKey() + "] must be set"); - } - if (REPOSITORY_TYPE_NAME.equals(delegateType)) { - throw new IllegalArgumentException( - "Cannot encrypt an already encrypted repository. [" - + DELEGATE_TYPE_SETTING.getKey() - + "] must not be equal to [" - + REPOSITORY_TYPE_NAME - + "]" - ); + @Override + public Repository create(RepositoryMetadata metadata) { + throw new UnsupportedOperationException(); } - final Repository.Factory factory = typeLookup.apply(delegateType); - if (null == factory || false == SUPPORTED_ENCRYPTED_TYPE_NAMES.contains(delegateType)) { - throw new IllegalArgumentException( - "Unsupported delegate repository type [" + delegateType + "] for setting [" + DELEGATE_TYPE_SETTING.getKey() + "]" + + @Override + public Repository create(RepositoryMetadata metadata, Function typeLookup) throws Exception { + final String delegateType = DELEGATE_TYPE_SETTING.get(metadata.settings()); + if (Strings.hasLength(delegateType) == false) { + throw new IllegalArgumentException("Repository setting [" + DELEGATE_TYPE_SETTING.getKey() + "] must be set"); + } + if (REPOSITORY_TYPE_NAME.equals(delegateType)) { + throw new IllegalArgumentException( + "Cannot encrypt an already encrypted repository. [" + + DELEGATE_TYPE_SETTING.getKey() + + "] must not be equal to [" + + REPOSITORY_TYPE_NAME + + "]" + ); + } + final Repository.Factory factory = typeLookup.apply(delegateType); + if (null == factory || false == SUPPORTED_ENCRYPTED_TYPE_NAMES.contains(delegateType)) { + throw new IllegalArgumentException( + "Unsupported delegate repository type [" + delegateType + "] for setting [" + DELEGATE_TYPE_SETTING.getKey() + "]" + ); + } + final String repositoryPasswordName = PASSWORD_NAME_SETTING.get(metadata.settings()); + if (Strings.hasLength(repositoryPasswordName) == false) { + throw new IllegalArgumentException("Repository setting [" + PASSWORD_NAME_SETTING.getKey() + "] must be set"); + } + final SecureString repositoryPassword = repositoryPasswordsMap.get(repositoryPasswordName); + if (repositoryPassword == null) { + throw new IllegalArgumentException( + "Secure setting [" + + ENCRYPTION_PASSWORD_SETTING.getConcreteSettingForNamespace(repositoryPasswordName).getKey() + + "] must be set" + ); + } + final Repository delegatedRepository = factory.create( + new RepositoryMetadata(metadata.name(), delegateType, metadata.settings()) ); - } - final String repositoryPasswordName = PASSWORD_NAME_SETTING.get(metadata.settings()); - if (Strings.hasLength(repositoryPasswordName) == false) { - throw new IllegalArgumentException("Repository setting [" + PASSWORD_NAME_SETTING.getKey() + "] must be set"); - } - final SecureString repositoryPassword = repositoryPasswordsMap.get(repositoryPasswordName); - if (repositoryPassword == null) { - throw new IllegalArgumentException( - "Secure setting [" - + ENCRYPTION_PASSWORD_SETTING.getConcreteSettingForNamespace(repositoryPasswordName).getKey() - + "] must be set" + if (false == (delegatedRepository instanceof BlobStoreRepository) || delegatedRepository instanceof EncryptedRepository) { + throw new IllegalArgumentException("Unsupported delegate repository type [" + DELEGATE_TYPE_SETTING.getKey() + "]"); + } + if (false == getLicenseState().isAllowed(XPackLicenseState.Feature.ENCRYPTED_SNAPSHOT)) { + logger.warn( + new ParameterizedMessage( + "Encrypted snapshots are not allowed for the currently installed license [{}]." + + " Snapshots to the [{}] encrypted repository are not permitted." + + " All the other operations, including restore, work without restrictions.", + getLicenseState().getOperationMode().description(), + metadata.name() + ), + LicenseUtils.newComplianceException("encrypted snapshots") + ); + } + return createEncryptedRepository( + metadata, + registry, + clusterService, + bigArrays, + recoverySettings, + (BlobStoreRepository) delegatedRepository, + () -> getLicenseState(), + repositoryPassword ); } - final Repository delegatedRepository = factory.create( - new RepositoryMetadata(metadata.name(), delegateType, metadata.settings()) - ); - if (false == (delegatedRepository instanceof BlobStoreRepository) || delegatedRepository instanceof EncryptedRepository) { - throw new IllegalArgumentException("Unsupported delegate repository type [" + DELEGATE_TYPE_SETTING.getKey() + "]"); - } - if (false == getLicenseState().isAllowed(XPackLicenseState.Feature.ENCRYPTED_SNAPSHOT)) { - logger.warn( - new ParameterizedMessage( - "Encrypted snapshots are not allowed for the currently installed license [{}]." - + " Snapshots to the [{}] encrypted repository are not permitted." - + " All the other operations, including restore, work without restrictions.", - getLicenseState().getOperationMode().description(), - metadata.name() - ), - LicenseUtils.newComplianceException("encrypted snapshots") - ); - } - return createEncryptedRepository( - metadata, - registry, - clusterService, - bigArrays, - recoverySettings, - (BlobStoreRepository) delegatedRepository, - () -> getLicenseState(), - repositoryPassword - ); - } - }); + }); + } else { + return Map.of(); + } } // protected for tests From e034d209788992fa7522fc93b0622a6a411fd14b Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Wed, 2 Dec 2020 16:59:20 +0200 Subject: [PATCH 2/6] Reverse condition to have a friendlier diff --- .../encrypted/EncryptedRepositoryPlugin.java | 140 +++++++++--------- 1 file changed, 70 insertions(+), 70 deletions(-) diff --git a/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java b/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java index 2400325632a04..64888bc6eac48 100644 --- a/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java +++ b/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java @@ -97,81 +97,81 @@ public Map getRepositories( } final Map repositoryPasswordsMap = Map.copyOf(repositoryPasswordsMapBuilder); - if (Build.CURRENT.isSnapshot() || (ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED != null && - ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED)) { - return Collections.singletonMap(REPOSITORY_TYPE_NAME, new Repository.Factory() { + if (false == Build.CURRENT.isSnapshot() && (ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED == null || + ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED == false)) { + return Map.of(); + } - @Override - public Repository create(RepositoryMetadata metadata) { - throw new UnsupportedOperationException(); - } + return Collections.singletonMap(REPOSITORY_TYPE_NAME, new Repository.Factory() { + + @Override + public Repository create(RepositoryMetadata metadata) { + throw new UnsupportedOperationException(); + } - @Override - public Repository create(RepositoryMetadata metadata, Function typeLookup) throws Exception { - final String delegateType = DELEGATE_TYPE_SETTING.get(metadata.settings()); - if (Strings.hasLength(delegateType) == false) { - throw new IllegalArgumentException("Repository setting [" + DELEGATE_TYPE_SETTING.getKey() + "] must be set"); - } - if (REPOSITORY_TYPE_NAME.equals(delegateType)) { - throw new IllegalArgumentException( - "Cannot encrypt an already encrypted repository. [" - + DELEGATE_TYPE_SETTING.getKey() - + "] must not be equal to [" - + REPOSITORY_TYPE_NAME - + "]" - ); - } - final Repository.Factory factory = typeLookup.apply(delegateType); - if (null == factory || false == SUPPORTED_ENCRYPTED_TYPE_NAMES.contains(delegateType)) { - throw new IllegalArgumentException( - "Unsupported delegate repository type [" + delegateType + "] for setting [" + DELEGATE_TYPE_SETTING.getKey() + "]" - ); - } - final String repositoryPasswordName = PASSWORD_NAME_SETTING.get(metadata.settings()); - if (Strings.hasLength(repositoryPasswordName) == false) { - throw new IllegalArgumentException("Repository setting [" + PASSWORD_NAME_SETTING.getKey() + "] must be set"); - } - final SecureString repositoryPassword = repositoryPasswordsMap.get(repositoryPasswordName); - if (repositoryPassword == null) { - throw new IllegalArgumentException( - "Secure setting [" - + ENCRYPTION_PASSWORD_SETTING.getConcreteSettingForNamespace(repositoryPasswordName).getKey() - + "] must be set" - ); - } - final Repository delegatedRepository = factory.create( - new RepositoryMetadata(metadata.name(), delegateType, metadata.settings()) + @Override + public Repository create(RepositoryMetadata metadata, Function typeLookup) throws Exception { + final String delegateType = DELEGATE_TYPE_SETTING.get(metadata.settings()); + if (Strings.hasLength(delegateType) == false) { + throw new IllegalArgumentException("Repository setting [" + DELEGATE_TYPE_SETTING.getKey() + "] must be set"); + } + if (REPOSITORY_TYPE_NAME.equals(delegateType)) { + throw new IllegalArgumentException( + "Cannot encrypt an already encrypted repository. [" + + DELEGATE_TYPE_SETTING.getKey() + + "] must not be equal to [" + + REPOSITORY_TYPE_NAME + + "]" ); - if (false == (delegatedRepository instanceof BlobStoreRepository) || delegatedRepository instanceof EncryptedRepository) { - throw new IllegalArgumentException("Unsupported delegate repository type [" + DELEGATE_TYPE_SETTING.getKey() + "]"); - } - if (false == getLicenseState().isAllowed(XPackLicenseState.Feature.ENCRYPTED_SNAPSHOT)) { - logger.warn( - new ParameterizedMessage( - "Encrypted snapshots are not allowed for the currently installed license [{}]." - + " Snapshots to the [{}] encrypted repository are not permitted." - + " All the other operations, including restore, work without restrictions.", - getLicenseState().getOperationMode().description(), - metadata.name() - ), - LicenseUtils.newComplianceException("encrypted snapshots") - ); - } - return createEncryptedRepository( - metadata, - registry, - clusterService, - bigArrays, - recoverySettings, - (BlobStoreRepository) delegatedRepository, - () -> getLicenseState(), - repositoryPassword + } + final Repository.Factory factory = typeLookup.apply(delegateType); + if (null == factory || false == SUPPORTED_ENCRYPTED_TYPE_NAMES.contains(delegateType)) { + throw new IllegalArgumentException( + "Unsupported delegate repository type [" + delegateType + "] for setting [" + DELEGATE_TYPE_SETTING.getKey() + "]" ); } - }); - } else { - return Map.of(); - } + final String repositoryPasswordName = PASSWORD_NAME_SETTING.get(metadata.settings()); + if (Strings.hasLength(repositoryPasswordName) == false) { + throw new IllegalArgumentException("Repository setting [" + PASSWORD_NAME_SETTING.getKey() + "] must be set"); + } + final SecureString repositoryPassword = repositoryPasswordsMap.get(repositoryPasswordName); + if (repositoryPassword == null) { + throw new IllegalArgumentException( + "Secure setting [" + + ENCRYPTION_PASSWORD_SETTING.getConcreteSettingForNamespace(repositoryPasswordName).getKey() + + "] must be set" + ); + } + final Repository delegatedRepository = factory.create( + new RepositoryMetadata(metadata.name(), delegateType, metadata.settings()) + ); + if (false == (delegatedRepository instanceof BlobStoreRepository) || delegatedRepository instanceof EncryptedRepository) { + throw new IllegalArgumentException("Unsupported delegate repository type [" + DELEGATE_TYPE_SETTING.getKey() + "]"); + } + if (false == getLicenseState().isAllowed(XPackLicenseState.Feature.ENCRYPTED_SNAPSHOT)) { + logger.warn( + new ParameterizedMessage( + "Encrypted snapshots are not allowed for the currently installed license [{}]." + + " Snapshots to the [{}] encrypted repository are not permitted." + + " All the other operations, including restore, work without restrictions.", + getLicenseState().getOperationMode().description(), + metadata.name() + ), + LicenseUtils.newComplianceException("encrypted snapshots") + ); + } + return createEncryptedRepository( + metadata, + registry, + clusterService, + bigArrays, + recoverySettings, + (BlobStoreRepository) delegatedRepository, + () -> getLicenseState(), + repositoryPassword + ); + } + }); } // protected for tests From 5cd760b0ac01c86ddabaf53464fea464a2bc212e Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Wed, 2 Dec 2020 17:02:34 +0200 Subject: [PATCH 3/6] Spotless and invert condition --- .../encrypted/EncryptedRepositoryPlugin.java | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java b/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java index 64888bc6eac48..edce84a531998 100644 --- a/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java +++ b/x-pack/plugin/repository-encrypted/src/main/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryPlugin.java @@ -53,7 +53,7 @@ public class EncryptedRepositoryPlugin extends Plugin implements RepositoryPlugi ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED = null; } else { throw new IllegalArgumentException( - "expected es.encrypted_repository_feature_flag_registered to be unset or [true|false] but was [" + property + "]" + "expected es.encrypted_repository_feature_flag_registered to be unset or [true|false] but was [" + property + "]" ); } } @@ -97,8 +97,8 @@ public Map getRepositories( } final Map repositoryPasswordsMap = Map.copyOf(repositoryPasswordsMapBuilder); - if (false == Build.CURRENT.isSnapshot() && (ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED == null || - ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED == false)) { + if (false == Build.CURRENT.isSnapshot() + && (ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED == null || ENCRYPTED_REPOSITORY_FEATURE_FLAG_REGISTERED == false)) { return Map.of(); } @@ -117,17 +117,17 @@ public Repository create(RepositoryMetadata metadata, Function getLicenseState(), - repositoryPassword + metadata, + registry, + clusterService, + bigArrays, + recoverySettings, + (BlobStoreRepository) delegatedRepository, + () -> getLicenseState(), + repositoryPassword ); } }); From f0d11582e236e79fb6338a35eca8bd29a6d3194d Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Mon, 21 Dec 2020 18:43:18 +0200 Subject: [PATCH 4/6] tests after writeblobatomic interface --- .../repositories/encrypted/EncryptedRepositoryTests.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/x-pack/plugin/repository-encrypted/src/test/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryTests.java b/x-pack/plugin/repository-encrypted/src/test/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryTests.java index a41f152c57dce..8e756971f7400 100644 --- a/x-pack/plugin/repository-encrypted/src/test/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryTests.java +++ b/x-pack/plugin/repository-encrypted/src/test/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryTests.java @@ -14,7 +14,6 @@ import org.elasticsearch.common.blobstore.BlobStore; import org.elasticsearch.common.bytes.BytesReference; import org.elasticsearch.common.collect.Tuple; -import org.elasticsearch.common.io.Streams; import org.elasticsearch.common.settings.SecureString; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.util.BigArrays; @@ -31,7 +30,6 @@ import javax.crypto.spec.SecretKeySpec; import java.io.ByteArrayInputStream; import java.io.IOException; -import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; @@ -42,7 +40,6 @@ import static org.hamcrest.Matchers.not; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyBoolean; -import static org.mockito.Matchers.anyLong; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -97,10 +94,10 @@ public void setUpMocks() throws Exception { // write atomic doAnswer(invocationOnMockBlobContainer -> { String DEKId = ((String) invocationOnMockBlobContainer.getArguments()[0]); - InputStream DEKInputStream = ((InputStream) invocationOnMockBlobContainer.getArguments()[1]); - this.blobsMap.put(blobPath.add(DEKId), BytesReference.toBytes(Streams.readFully(DEKInputStream))); + this.blobsMap.put(blobPath.add(DEKId), + BytesReference.toBytes((BytesReference) invocationOnMockBlobContainer.getArguments()[1])); return null; - }).when(blobContainer).writeBlobAtomic(any(String.class), any(InputStream.class), anyLong(), anyBoolean()); + }).when(blobContainer).writeBlobAtomic(any(String.class), any(BytesReference.class), anyBoolean()); // read doAnswer(invocationOnMockBlobContainer -> { String DEKId = ((String) invocationOnMockBlobContainer.getArguments()[0]); From 70a3e6c348da0ae6a0c7287fb51562d2b1a5cabe Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Mon, 21 Dec 2020 18:44:35 +0200 Subject: [PATCH 5/6] Spotless --- .../repositories/encrypted/EncryptedRepositoryTests.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/x-pack/plugin/repository-encrypted/src/test/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryTests.java b/x-pack/plugin/repository-encrypted/src/test/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryTests.java index 8e756971f7400..9dad85850bf11 100644 --- a/x-pack/plugin/repository-encrypted/src/test/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryTests.java +++ b/x-pack/plugin/repository-encrypted/src/test/java/org/elasticsearch/repositories/encrypted/EncryptedRepositoryTests.java @@ -94,8 +94,10 @@ public void setUpMocks() throws Exception { // write atomic doAnswer(invocationOnMockBlobContainer -> { String DEKId = ((String) invocationOnMockBlobContainer.getArguments()[0]); - this.blobsMap.put(blobPath.add(DEKId), - BytesReference.toBytes((BytesReference) invocationOnMockBlobContainer.getArguments()[1])); + this.blobsMap.put( + blobPath.add(DEKId), + BytesReference.toBytes((BytesReference) invocationOnMockBlobContainer.getArguments()[1]) + ); return null; }).when(blobContainer).writeBlobAtomic(any(String.class), any(BytesReference.class), anyBoolean()); // read From 2b4ebdcff2211f53a1a3735502ac3981b7306302 Mon Sep 17 00:00:00 2001 From: Albert Zaharovits Date: Tue, 22 Dec 2020 14:21:51 +0200 Subject: [PATCH 6/6] Gradle fix --- x-pack/plugin/repository-encrypted/build.gradle | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/x-pack/plugin/repository-encrypted/build.gradle b/x-pack/plugin/repository-encrypted/build.gradle index 34b9e2aea320f..33401df941209 100644 --- a/x-pack/plugin/repository-encrypted/build.gradle +++ b/x-pack/plugin/repository-encrypted/build.gradle @@ -19,7 +19,12 @@ dependencies { // required for integ tests of encrypted cloud repositories internalClusterTestImplementation project(path: ':plugins:repository-gcs', configuration: 'internalClusterTestArtifacts') internalClusterTestImplementation project(path: ':plugins:repository-azure', configuration: 'internalClusterTestArtifacts') - internalClusterTestImplementation project(path: ':plugins:repository-s3', configuration: 'internalClusterTestArtifacts') + internalClusterTestImplementation(project(path: ':plugins:repository-s3', configuration: 'internalClusterTestArtifacts')) { + // HACK, resolves jar hell, such as: + // jar1: jakarta.xml.bind/jakarta.xml.bind-api/2.3.2/8d49996a4338670764d7ca4b85a1c4ccf7fe665d/jakarta.xml.bind-api-2.3.2.jar + // jar2: javax.xml.bind/jaxb-api/2.2.2/aeb3021ca93dde265796d82015beecdcff95bf09/jaxb-api-2.2.2.jar + exclude group: 'javax.xml.bind', module: 'jaxb-api' + } // for encrypted GCS repository integ tests internalClusterTestRuntimeOnly 'com.google.guava:guava:26.0-jre' } \ No newline at end of file