diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
index 278b9e773ae1f..01e1092f53d00 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/HardcodedEntitlements.java
@@ -92,8 +92,9 @@ private static List createServerEntitlements(Path pidFile) {
new CreateClassLoaderEntitlement(),
new FilesEntitlement(
List.of(
- // TODO: what in es.base is accessing shared repo?
+ // necessary due to lack of delegation ES-12382
FilesEntitlement.FileData.ofBaseDirPath(SHARED_REPO, READ_WRITE),
+ FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)
)
)
@@ -122,6 +123,7 @@ private static List createServerEntitlements(Path pidFile) {
new FilesEntitlement(
List.of(
FilesEntitlement.FileData.ofBaseDirPath(CONFIG, READ),
+ FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)
)
)
@@ -130,7 +132,12 @@ private static List createServerEntitlements(Path pidFile) {
new Scope(
"org.apache.lucene.misc",
List.of(
- new FilesEntitlement(List.of(FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE))),
+ new FilesEntitlement(
+ List.of(
+ FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
+ FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)
+ )
+ ),
new ReadStoreAttributesEntitlement()
)
),
@@ -145,7 +152,12 @@ private static List createServerEntitlements(Path pidFile) {
"org.elasticsearch.nativeaccess",
List.of(
new LoadNativeLibrariesEntitlement(),
- new FilesEntitlement(List.of(FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)))
+ new FilesEntitlement(
+ List.of(
+ FilesEntitlement.FileData.ofBaseDirPath(SHARED_DATA, READ_WRITE),
+ FilesEntitlement.FileData.ofBaseDirPath(DATA, READ_WRITE)
+ )
+ )
)
)
);
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
index 7f0541911284c..df68da2e251ac 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/PolicyManager.java
@@ -367,9 +367,7 @@ private ModuleEntitlements getModuleScopeEntitlements(
* @return true if permission is granted regardless of the entitlement
*/
boolean isTriviallyAllowed(Class> requestingClass) {
- if (generalLogger.isTraceEnabled()) {
- generalLogger.trace("Stack trace for upcoming trivially-allowed check", new Exception());
- }
+ // note: do not log exceptions in here, this could interfere with loading of additionally necessary classes such as ThrowableProxy
if (requestingClass == null) {
generalLogger.debug("Entitlement trivially allowed: no caller frames outside the entitlement library");
return true;
diff --git a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java
index 872a083a76ba6..cc9ef9d263dd1 100644
--- a/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java
+++ b/libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java
@@ -182,8 +182,9 @@ private static BaseDir parseBaseDir(String baseDir) {
case "config" -> BaseDir.CONFIG;
case "data" -> BaseDir.DATA;
case "home" -> BaseDir.USER_HOME;
+ case "shared_data" -> BaseDir.SHARED_DATA;
// it would be nice to limit this to just ES modules, but we don't have a way to plumb that through to here
- // however, we still don't document in the error case below that shared_repo is valid
+ // however, we still don't document in the error case below that shared_repo and shared_data is valid
case "shared_repo" -> BaseDir.SHARED_REPO;
default -> throw new PolicyValidationException(
"invalid relative directory: " + baseDir + ", valid values: [config, data, home]"
diff --git a/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java b/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java
index c6c1868d5bbc1..493f4d10eea6d 100644
--- a/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java
+++ b/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureBlobStoreRepositoryTests.java
@@ -41,6 +41,7 @@
import org.elasticsearch.telemetry.Measurement;
import org.elasticsearch.telemetry.TestTelemetryPlugin;
import org.elasticsearch.test.BackgroundIndexer;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import java.io.ByteArrayInputStream;
@@ -73,6 +74,7 @@
import static org.hamcrest.Matchers.is;
@SuppressForbidden(reason = "this test uses a HttpServer to emulate an Azure endpoint")
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class AzureBlobStoreRepositoryTests extends ESMockAPIBasedRepositoryIntegTestCase {
protected static final String DEFAULT_ACCOUNT_NAME = "account";
diff --git a/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureRepositoryMissingCredentialsIT.java b/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureRepositoryMissingCredentialsIT.java
index 947f73c2ce580..5e3cad4534b7c 100644
--- a/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureRepositoryMissingCredentialsIT.java
+++ b/modules/repository-azure/src/internalClusterTest/java/org/elasticsearch/repositories/azure/AzureRepositoryMissingCredentialsIT.java
@@ -18,12 +18,14 @@
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.repositories.RepositoryVerificationException;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import java.util.Collection;
import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.containsString;
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class AzureRepositoryMissingCredentialsIT extends ESIntegTestCase {
@Override
diff --git a/plugins/store-smb/src/main/plugin-metadata/entitlement-policy.yaml b/plugins/store-smb/src/main/plugin-metadata/entitlement-policy.yaml
index 1022253171a11..dbe45c7527967 100644
--- a/plugins/store-smb/src/main/plugin-metadata/entitlement-policy.yaml
+++ b/plugins/store-smb/src/main/plugin-metadata/entitlement-policy.yaml
@@ -3,3 +3,6 @@ ALL-UNNAMED:
- relative_path: "indices/"
relative_to: data
mode: read_write
+ - relative_path: ""
+ relative_to: shared_data
+ mode: read_write
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
index 83e79ff7f45a8..82a6c1f6acf85 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/ReloadSecureSettingsIT.java
@@ -27,6 +27,7 @@
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.plugins.ReloadablePlugin;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.junit.BeforeClass;
import java.io.InputStream;
@@ -47,6 +48,7 @@
import static org.hamcrest.Matchers.nullValue;
@ESIntegTestCase.ClusterScope(minNumDataNodes = 2)
+@ESTestCase.WithoutEntitlements // requires entitlement delegation ES-10920
public class ReloadSecureSettingsIT extends ESIntegTestCase {
private static final String VALID_SECURE_SETTING_NAME = "some.setting.that.exists";
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/tasks/PendingTasksBlocksIT.java b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/tasks/PendingTasksBlocksIT.java
index 6475e80901ea7..bb048179a437a 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/tasks/PendingTasksBlocksIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/action/admin/cluster/tasks/PendingTasksBlocksIT.java
@@ -12,6 +12,7 @@
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.gateway.GatewayService;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.InternalTestCluster;
import java.util.Arrays;
@@ -22,6 +23,7 @@
import static org.elasticsearch.cluster.metadata.IndexMetadata.SETTING_READ_ONLY;
import static org.elasticsearch.cluster.metadata.IndexMetadata.SETTING_READ_ONLY_ALLOW_DELETE;
+@ESTestCase.WithoutEntitlements // requires entitlement delegation ES-10920
public class PendingTasksBlocksIT extends ESIntegTestCase {
public void testPendingTasksWithIndexBlocks() {
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveCustomsCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveCustomsCommandIT.java
index 2b2dc114e8ffc..e88a08f983b90 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveCustomsCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveCustomsCommandIT.java
@@ -18,12 +18,14 @@
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import java.util.Map;
import static org.hamcrest.Matchers.containsString;
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoManageMasterNodes = false)
+@ESTestCase.WithoutEntitlements // commands don't run with entitlements enforced
public class RemoveCustomsCommandIT extends ESIntegTestCase {
public void testRemoveCustomsAbortedByUser() throws Exception {
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveIndexSettingsCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveIndexSettingsCommandIT.java
index 65e325a1291d8..62afa9c57cbaa 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveIndexSettingsCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveIndexSettingsCommandIT.java
@@ -21,6 +21,7 @@
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import java.util.Collection;
import java.util.List;
@@ -31,6 +32,7 @@
import static org.hamcrest.Matchers.not;
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoManageMasterNodes = false)
+@ESTestCase.WithoutEntitlements // commands don't run with entitlements enforced
public class RemoveIndexSettingsCommandIT extends ESIntegTestCase {
static final Setting FOO = Setting.intSetting("index.foo", 1, Setting.Property.IndexScope, Setting.Property.Dynamic);
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveSettingsCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveSettingsCommandIT.java
index d7ed6bb47b98b..1a68211c6ea8e 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveSettingsCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/cluster/coordination/RemoveSettingsCommandIT.java
@@ -19,6 +19,7 @@
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.TestEnvironment;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import java.util.Map;
@@ -27,6 +28,7 @@
import static org.hamcrest.Matchers.not;
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0, autoManageMasterNodes = false)
+@ESTestCase.WithoutEntitlements // commands don't run with entitlements enforced
public class RemoveSettingsCommandIT extends ESIntegTestCase {
public void testRemoveSettingsAbortedByUser() throws Exception {
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/discovery/single/SingleNodeDiscoveryIT.java b/server/src/internalClusterTest/java/org/elasticsearch/discovery/single/SingleNodeDiscoveryIT.java
index 10f13f6ab152f..c7780b7b0d2dd 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/discovery/single/SingleNodeDiscoveryIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/discovery/single/SingleNodeDiscoveryIT.java
@@ -87,7 +87,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
0,
"other",
Arrays.asList(getTestTransportPlugin(), MockHttpTransport.TestPlugin.class),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
try {
other.beforeTest(random());
@@ -137,7 +138,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
0,
"other",
Arrays.asList(getTestTransportPlugin(), MockHttpTransport.TestPlugin.class),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
try (var mockLog = MockLog.capture(JoinHelper.class)) {
mockLog.addExpectation(
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandIT.java b/server/src/internalClusterTest/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandIT.java
index b9513dfb95187..d1cff7b2a30d1 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/index/shard/RemoveCorruptedShardDataCommandIT.java
@@ -58,6 +58,7 @@
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.CorruptionUtils;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.InternalSettingsPlugin;
import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.test.engine.MockEngineSupport;
@@ -93,6 +94,7 @@
import static org.hamcrest.Matchers.startsWith;
@ESIntegTestCase.ClusterScope(scope = ESIntegTestCase.Scope.TEST, numDataNodes = 0)
+@ESTestCase.WithoutEntitlements // commands don't run with entitlements enforced
public class RemoveCorruptedShardDataCommandIT extends ESIntegTestCase {
@Override
diff --git a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/MultiClusterRepoAccessIT.java b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/MultiClusterRepoAccessIT.java
index c1549c1f3d384..1ee449d8af894 100644
--- a/server/src/internalClusterTest/java/org/elasticsearch/snapshots/MultiClusterRepoAccessIT.java
+++ b/server/src/internalClusterTest/java/org/elasticsearch/snapshots/MultiClusterRepoAccessIT.java
@@ -77,7 +77,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
InternalSettingsPlugin.class,
getTestTransportPlugin()
),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
secondCluster.beforeTest(random());
}
diff --git a/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java b/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
index 04e59e5476f3b..230e105feca18 100644
--- a/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
+++ b/server/src/test/java/org/elasticsearch/bootstrap/EntitlementMetaTests.java
@@ -10,9 +10,8 @@
package org.elasticsearch.bootstrap;
import org.elasticsearch.core.SuppressForbidden;
-import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementsRule;
import org.elasticsearch.test.ESTestCase;
-import org.elasticsearch.test.ESTestCase.WithEntitlementsOnTestCode;
import java.io.IOException;
import java.nio.file.Path;
@@ -42,7 +41,7 @@
*/
public class EntitlementMetaTests extends ESTestCase {
public void testSelfTestPasses() {
- assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+ assumeTrue("Not yet working in serverless", TestEntitlementsRule.isEnabledForTest());
Elasticsearch.entitlementSelfTest();
}
diff --git a/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java b/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
index c126490922e48..14e3803fa6bad 100644
--- a/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
+++ b/server/src/test/java/org/elasticsearch/bootstrap/WithEntitlementsOnTestCodeMetaTests.java
@@ -10,7 +10,7 @@
package org.elasticsearch.bootstrap;
import org.elasticsearch.core.SuppressForbidden;
-import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementsRule;
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.ESTestCase.WithEntitlementsOnTestCode;
@@ -30,13 +30,13 @@ public class WithEntitlementsOnTestCodeMetaTests extends ESTestCase {
* is called from server code. The self-test should pass as usual.
*/
public void testSelfTestPasses() {
- assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+ assumeTrue("Not yet working in serverless", TestEntitlementsRule.isEnabledForTest());
Elasticsearch.entitlementSelfTest();
}
@SuppressForbidden(reason = "Testing that a forbidden API is disallowed")
public void testForbiddenActionDenied() {
- assumeTrue("Not yet working in serverless", TestEntitlementBootstrap.isEnabledForTest());
+ assumeTrue("Not yet working in serverless", TestEntitlementsRule.isEnabledForTest());
assertThrows(NotEntitledException.class, () -> Path.of(".").toRealPath());
}
}
diff --git a/server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java b/server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java
index a48ba63882734..78df6c9e88c65 100644
--- a/server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java
+++ b/server/src/test/java/org/elasticsearch/indices/IndicesServiceCloseTests.java
@@ -77,7 +77,8 @@ private Node startNode() throws NodeValidationException {
Node node = new MockNode(
settings,
Arrays.asList(getTestTransportPlugin(), MockHttpTransport.TestPlugin.class, InternalSettingsPlugin.class),
- true
+ true,
+ () -> {}
);
node.start();
return node;
diff --git a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
index bf53f14bc9e46..69dbb7061c948 100644
--- a/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
+++ b/test/framework/src/main/java/org/elasticsearch/bootstrap/BootstrapForTesting.java
@@ -15,7 +15,7 @@
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.core.Booleans;
import org.elasticsearch.core.PathUtils;
-import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementsRule;
import org.elasticsearch.jdk.JarHell;
import java.io.IOException;
@@ -75,7 +75,7 @@ public class BootstrapForTesting {
// Fire up entitlements
try {
- TestEntitlementBootstrap.bootstrap(javaTmpDir);
+ TestEntitlementsRule.initialize(javaTmpDir);
} catch (IOException e) {
throw new IllegalStateException(e.getClass().getSimpleName() + " while initializing entitlements for tests", e);
}
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementsRule.java
similarity index 51%
rename from test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
rename to test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementsRule.java
index 1edc0b4763abb..8b56f59b9ac10 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementBootstrap.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/bootstrap/TestEntitlementsRule.java
@@ -9,26 +9,32 @@
package org.elasticsearch.entitlement.bootstrap;
+import org.apache.lucene.tests.mockfile.FilterPath;
import org.elasticsearch.bootstrap.TestBuildInfo;
import org.elasticsearch.bootstrap.TestBuildInfoParser;
import org.elasticsearch.bootstrap.TestScopeResolver;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.core.Booleans;
-import org.elasticsearch.core.Nullable;
import org.elasticsearch.core.PathUtils;
import org.elasticsearch.core.SuppressForbidden;
import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
import org.elasticsearch.entitlement.runtime.policy.PathLookup;
import org.elasticsearch.entitlement.runtime.policy.PathLookup.BaseDir;
import org.elasticsearch.entitlement.runtime.policy.Policy;
+import org.elasticsearch.entitlement.runtime.policy.PolicyManager;
import org.elasticsearch.entitlement.runtime.policy.PolicyParser;
import org.elasticsearch.entitlement.runtime.policy.TestPathLookup;
import org.elasticsearch.entitlement.runtime.policy.TestPolicyManager;
import org.elasticsearch.logging.LogManager;
import org.elasticsearch.logging.Logger;
import org.elasticsearch.plugins.PluginDescriptor;
+import org.elasticsearch.test.ESTestCase;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
@@ -38,13 +44,14 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Consumer;
@@ -56,122 +63,184 @@
import static org.elasticsearch.env.Environment.PATH_REPO_SETTING;
import static org.elasticsearch.env.Environment.PATH_SHARED_DATA_SETTING;
-public class TestEntitlementBootstrap {
+public class TestEntitlementsRule implements TestRule {
+ private static final Logger logger = LogManager.getLogger(TestEntitlementsRule.class);
- private static final Logger logger = LogManager.getLogger(TestEntitlementBootstrap.class);
+ private static final Map> BASE_DIR_PATHS = new ConcurrentHashMap<>();
+ private static final TestPolicyManager POLICY_MANAGER;
- private static Map> baseDirPaths = new ConcurrentHashMap<>();
- private static TestPolicyManager policyManager;
-
- /**
- * Activates entitlement checking in tests.
- */
- public static void bootstrap(@Nullable Path tempDir) throws IOException {
- if (isEnabledForTest() == false) {
- return;
+ static {
+ PathLookup pathLookup = new TestPathLookup(BASE_DIR_PATHS);
+ try {
+ if (isEnabledForTest()) {
+ POLICY_MANAGER = createPolicyManager(pathLookup);
+ loadAgent(POLICY_MANAGER, pathLookup);
+ } else {
+ POLICY_MANAGER = null;
+ }
+ } catch (IOException e) {
+ throw new AssertionError(e);
}
- var previousTempDir = baseDirPaths.put(TEMP, zeroOrOne(tempDir));
- assert previousTempDir == null : "Test entitlement bootstrap called multiple times";
- TestPathLookup pathLookup = new TestPathLookup(baseDirPaths);
- policyManager = createPolicyManager(pathLookup);
- EntitlementInitialization.initializeArgs = new EntitlementInitialization.InitializeArgs(pathLookup, Set.of(), policyManager);
- logger.debug("Loading entitlement agent");
- EntitlementBootstrap.loadAgent(EntitlementBootstrap.findAgentJar(), EntitlementInitialization.class.getName());
}
- public static void registerNodeBaseDirs(Settings settings, Path configPath) {
- if (policyManager == null) {
- return;
+ public static void initialize(Path tempDir) throws IOException {
+ if (POLICY_MANAGER != null) {
+ var previousTempDir = BASE_DIR_PATHS.put(TEMP, List.of(tempDir));
+ assert previousTempDir == null : "Test entitlement bootstrap called multiple times";
}
- Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings));
- Path configDir = configPath != null ? configPath : homeDir.resolve("config");
- Collection dataDirs = dataDirs(settings, homeDir);
- Collection sharedDataDir = sharedDataDir(settings);
- Collection repoDirs = repoDirs(settings);
- logger.debug("Registering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs);
- baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.add(configDir)));
- baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.addAll(dataDirs)));
- baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.addAll(sharedDataDir)));
- baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.addAll(repoDirs)));
- policyManager.reset();
}
- public static void unregisterNodeBaseDirs(Settings settings, Path configPath) {
- if (policyManager == null) {
- return;
+ @Override
+ public Statement apply(Statement base, Description description) {
+ assert description.isSuite() : "must be used as ClassRule";
+
+ // class / suite level
+ boolean withoutEntitlements = description.getAnnotation(ESTestCase.WithoutEntitlements.class) != null;
+ boolean withEntitlementsOnTestCode = description.getAnnotation(ESTestCase.WithEntitlementsOnTestCode.class) != null;
+ var entitledPackages = description.getAnnotation(ESTestCase.EntitledTestPackages.class);
+
+ if (POLICY_MANAGER != null) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ POLICY_MANAGER.setActive(false == withoutEntitlements);
+ POLICY_MANAGER.setTriviallyAllowingTestCode(false == withEntitlementsOnTestCode);
+ if (entitledPackages != null) {
+ assert entitledPackages.value().length > 0 : "No test packages specified in @EntitledTestPackages";
+ POLICY_MANAGER.setEntitledTestPackages(entitledPackages.value());
+ } else {
+ POLICY_MANAGER.setEntitledTestPackages();
+ }
+ BASE_DIR_PATHS.keySet().retainAll(List.of(TEMP));
+ POLICY_MANAGER.clearModuleEntitlementsCache();
+ // evaluate the suite
+ base.evaluate();
+ } finally {
+ POLICY_MANAGER.setActive(false);
+ POLICY_MANAGER.setTriviallyAllowingTestCode(true);
+ POLICY_MANAGER.setEntitledTestPackages();
+ BASE_DIR_PATHS.keySet().retainAll(List.of(TEMP));
+ POLICY_MANAGER.clearModuleEntitlementsCache();
+ }
+ }
+ };
+ } else if (withEntitlementsOnTestCode) {
+ throw new AssertionError(
+ "Cannot use @WithEntitlementsOnTestCode on tests that are not configured to use entitlements for testing"
+ );
+ } else {
+ return base;
}
- Path homeDir = absolutePath(PATH_HOME_SETTING.get(settings));
- Path configDir = configPath != null ? configPath : homeDir.resolve("config");
- Collection dataDirs = dataDirs(settings, homeDir);
- Collection sharedDataDir = sharedDataDir(settings);
- Collection repoDirs = repoDirs(settings);
- logger.debug("Unregistering node dirs: config [{}], dataDirs [{}], repoDirs [{}]", configDir, dataDirs, repoDirs);
- baseDirPaths.compute(BaseDir.CONFIG, baseDirModifier(paths -> paths.remove(configDir)));
- baseDirPaths.compute(BaseDir.DATA, baseDirModifier(paths -> paths.removeAll(dataDirs)));
- baseDirPaths.compute(BaseDir.SHARED_DATA, baseDirModifier(paths -> paths.removeAll(sharedDataDir)));
- baseDirPaths.compute(BaseDir.SHARED_REPO, baseDirModifier(paths -> paths.removeAll(repoDirs)));
- policyManager.reset();
}
- private static Collection dataDirs(Settings settings, Path homeDir) {
- List dataDirs = PATH_DATA_SETTING.get(settings);
- return dataDirs.isEmpty()
- ? List.of(homeDir.resolve("data"))
- : dataDirs.stream().map(TestEntitlementBootstrap::absolutePath).toList();
- }
+ /**
+ * Creates a entitlement grant for node specific paths.
+ */
+ public Closeable newNodeGrant(Settings settings, Path configPath) {
+ if (POLICY_MANAGER == null) {
+ return () -> {}; // noop if not running with entitlements
+ }
- private static Collection sharedDataDir(Settings settings) {
- String sharedDataDir = PATH_SHARED_DATA_SETTING.get(settings);
- return Strings.hasText(sharedDataDir) ? List.of(absolutePath(sharedDataDir)) : List.of();
+ var unwrappedConfigPath = configPath;
+ while (unwrappedConfigPath instanceof FilterPath fPath) {
+ unwrappedConfigPath = fPath.getDelegate();
+ }
+ NodeGrant nodeGrant = new NodeGrant(settings, unwrappedConfigPath, this::revokeGrant);
+ addGrant(nodeGrant);
+ return nodeGrant;
}
- private static Collection repoDirs(Settings settings) {
- return PATH_REPO_SETTING.get(settings).stream().map(TestEntitlementBootstrap::absolutePath).toList();
+ /**
+ * Revoke all open node grants.
+ */
+ public void revokeNodeGrants() {
+ BASE_DIR_PATHS.keySet().retainAll(List.of(TEMP));
+ POLICY_MANAGER.clearModuleEntitlementsCache();
}
- private static BiFunction, Collection> baseDirModifier(Consumer> consumer) {
- return (BaseDir baseDir, Collection paths) -> {
- if (paths == null) {
- paths = new HashSet<>();
- }
- consumer.accept(paths);
- return paths;
- };
- }
+ private record NodeGrant(Settings settings, Path configPath, Consumer onClose) implements Closeable {
+ private Path homeDir() {
+ return absolutePath(PATH_HOME_SETTING.get(settings));
+ }
- @SuppressForbidden(reason = "must be resolved using the default file system, rather then the mocked test file system")
- private static Path absolutePath(String path) {
- return Paths.get(path).toAbsolutePath().normalize();
- }
+ private Path configDir() {
+ return configPath != null ? configPath : homeDir().resolve("config");
+ }
- private static List zeroOrOne(T item) {
- if (item == null) {
- return List.of();
- } else {
- return List.of(item);
+ private Path[] dataDirs() {
+ List dataDirs = PATH_DATA_SETTING.get(settings);
+ return dataDirs.isEmpty()
+ ? new Path[] { homeDir().resolve("data") }
+ : dataDirs.stream().map(NodeGrant::absolutePath).toArray(Path[]::new);
}
- }
- public static boolean isEnabledForTest() {
- return Booleans.parseBoolean(System.getProperty("es.entitlement.enableForTests", "false"));
+ private Path[] sharedDataDir() {
+ String sharedDataDir = PATH_SHARED_DATA_SETTING.get(settings);
+ return Strings.hasText(sharedDataDir) ? new Path[] { absolutePath(sharedDataDir) } : new Path[0];
+ }
+
+ private Path[] repoDirs() {
+ return PATH_REPO_SETTING.get(settings).stream().map(NodeGrant::absolutePath).toArray(Path[]::new);
+ }
+
+ @SuppressForbidden(reason = "must be resolved using the default file system, rather then the mocked test file system")
+ private static Path absolutePath(String path) {
+ return Paths.get(path).toAbsolutePath().normalize();
+ }
+
+ @Override
+ public void close() {
+ onClose.accept(this);
+ }
+
+ @Override
+ public String toString() {
+ return Strings.format(
+ "NodeGrant[configDir=%s, dataDirs=%s, sharedDataDir=%s, repoDirs=%s]",
+ configDir(),
+ dataDirs(),
+ sharedDataDir(),
+ repoDirs()
+ );
+ }
}
- public static void setActive(boolean newValue) {
- policyManager.setActive(newValue);
+ private void addGrant(NodeGrant nodeGrant) {
+ logger.debug("Adding node grant: {}", nodeGrant);
+ BASE_DIR_PATHS.compute(BaseDir.CONFIG, baseDirModifier(Collection::add, nodeGrant.configDir()));
+ BASE_DIR_PATHS.compute(BaseDir.DATA, baseDirModifier(Collection::add, nodeGrant.dataDirs()));
+ BASE_DIR_PATHS.compute(BaseDir.SHARED_DATA, baseDirModifier(Collection::add, nodeGrant.sharedDataDir()));
+ BASE_DIR_PATHS.compute(BaseDir.SHARED_REPO, baseDirModifier(Collection::add, nodeGrant.repoDirs()));
+ POLICY_MANAGER.clearModuleEntitlementsCache();
}
- public static void setTriviallyAllowingTestCode(boolean newValue) {
- policyManager.setTriviallyAllowingTestCode(newValue);
+ private void revokeGrant(NodeGrant nodeGrant) {
+ logger.debug("Revoking node grant: {}", nodeGrant);
+ BASE_DIR_PATHS.compute(BaseDir.CONFIG, baseDirModifier(Collection::remove, nodeGrant.configDir()));
+ BASE_DIR_PATHS.compute(BaseDir.DATA, baseDirModifier(Collection::remove, nodeGrant.dataDirs()));
+ BASE_DIR_PATHS.compute(BaseDir.SHARED_DATA, baseDirModifier(Collection::remove, nodeGrant.sharedDataDir()));
+ BASE_DIR_PATHS.compute(BaseDir.SHARED_REPO, baseDirModifier(Collection::remove, nodeGrant.repoDirs()));
+ POLICY_MANAGER.clearModuleEntitlementsCache();
}
- public static void setEntitledTestPackages(String[] entitledTestPackages) {
- policyManager.setEntitledTestPackages(entitledTestPackages);
+ // This must allow for duplicate paths between nodes, the config dir for instance is shared across all nodes.
+ private static BiFunction, Collection> baseDirModifier(
+ BiConsumer, Path> operation,
+ Path... updates
+ ) {
+ // always return a new unmodifiable copy
+ return (BaseDir baseDir, Collection paths) -> {
+ paths = paths == null ? new ArrayList<>() : new ArrayList<>(paths);
+ for (Path update : updates) {
+ operation.accept(paths, update);
+ }
+ return Collections.unmodifiableCollection(paths);
+ };
}
- public static void reset() {
- if (policyManager != null) {
- policyManager.reset();
- }
+ public static boolean isEnabledForTest() {
+ return Booleans.parseBoolean(System.getProperty("es.entitlement.enableForTests", "false"));
}
private static TestPolicyManager createPolicyManager(PathLookup pathLookup) throws IOException {
@@ -229,6 +298,12 @@ private static TestPolicyManager createPolicyManager(PathLookup pathLookup) thro
);
}
+ private static void loadAgent(PolicyManager policyManager, PathLookup pathLookup) {
+ logger.debug("Loading entitlement agent");
+ EntitlementInitialization.initializeArgs = new EntitlementInitialization.InitializeArgs(pathLookup, Set.of(), policyManager);
+ EntitlementBootstrap.loadAgent(EntitlementBootstrap.findAgentJar(), EntitlementInitialization.class.getName());
+ }
+
private static Map parsePluginsPolicies(List pluginsData) {
Map policies = new HashMap<>();
for (var pluginData : pluginsData) {
diff --git a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
index b504e51e119f7..5eac4bad38bc1 100644
--- a/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
+++ b/test/framework/src/main/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManager.java
@@ -29,8 +29,8 @@
public class TestPolicyManager extends PolicyManager {
- boolean isActive;
- boolean isTriviallyAllowingTestCode;
+ boolean isActive = true;
+ boolean isTriviallyAllowingTestCode = true;
String[] entitledTestPackages = TEST_FRAMEWORK_PACKAGE_PREFIXES;
/**
@@ -53,7 +53,6 @@ public TestPolicyManager(
super(serverPolicy, apmAgentEntitlements, pluginPolicies, scopeResolver, name -> classpath, pathLookup);
this.classpath = classpath;
this.testOnlyClasspath = testOnlyClasspath;
- reset();
}
public void setActive(boolean newValue) {
@@ -65,23 +64,27 @@ public void setTriviallyAllowingTestCode(boolean newValue) {
}
public void setEntitledTestPackages(String... entitledTestPackages) {
+ if (entitledTestPackages == null || entitledTestPackages.length == 0) {
+ this.entitledTestPackages = TEST_FRAMEWORK_PACKAGE_PREFIXES; // already validated and sorted
+ return;
+ }
+
assertNoRedundantPrefixes(TEST_FRAMEWORK_PACKAGE_PREFIXES, entitledTestPackages, false);
if (entitledTestPackages.length > 1) {
assertNoRedundantPrefixes(entitledTestPackages, entitledTestPackages, true);
}
- String[] packages = ArrayUtils.concat(this.entitledTestPackages, entitledTestPackages);
+ String[] packages = ArrayUtils.concat(TEST_FRAMEWORK_PACKAGE_PREFIXES, entitledTestPackages);
Arrays.sort(packages);
this.entitledTestPackages = packages;
}
/**
- * Called between tests so each test is not affected by prior tests
+ * Clear cached module entitlements.
+ * This is required after updating entries in {@link TestPathLookup}.
*/
- public final void reset() {
+ public final void clearModuleEntitlementsCache() {
assert moduleEntitlementsMap.isEmpty() : "We're not supposed to be using moduleEntitlementsMap in tests";
classEntitlementsMap.clear();
- isActive = false;
- isTriviallyAllowingTestCode = true;
}
@Override
diff --git a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
index 3d5229435e729..d3d96b5102479 100644
--- a/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
+++ b/test/framework/src/main/java/org/elasticsearch/node/MockNode.java
@@ -24,7 +24,7 @@
import org.elasticsearch.common.util.MockBigArrays;
import org.elasticsearch.common.util.MockPageCacheRecycler;
import org.elasticsearch.common.util.PageCacheRecycler;
-import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.core.IOUtils;
import org.elasticsearch.env.Environment;
import org.elasticsearch.http.HttpServerTransport;
import org.elasticsearch.indices.ExecutorSelector;
@@ -54,11 +54,12 @@
import org.elasticsearch.transport.TransportService;
import org.elasticsearch.transport.TransportSettings;
-import java.io.IOException;
+import java.io.Closeable;
import java.nio.file.Path;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
+import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.LongSupplier;
@@ -237,32 +238,37 @@ protected HttpServerTransport newHttpTransport(PluginsService pluginsService, Ne
}
private final Collection> classpathPlugins;
+ // handle for node paths specific entitlement grants
+ private final Closeable entitlementGrant;
public MockNode(final Settings settings, final Collection> classpathPlugins) {
- this(settings, classpathPlugins, true);
+ this(settings, classpathPlugins, true, () -> {});
}
public MockNode(
final Settings settings,
final Collection> classpathPlugins,
- final boolean forbidPrivateIndexSettings
+ final boolean forbidPrivateIndexSettings,
+ final Closeable entitlementGrant
) {
- this(settings, classpathPlugins, null, forbidPrivateIndexSettings);
+ this(settings, classpathPlugins, null, forbidPrivateIndexSettings, entitlementGrant);
}
public MockNode(
final Settings settings,
final Collection> classpathPlugins,
final Path configPath,
- final boolean forbidPrivateIndexSettings
+ final boolean forbidPrivateIndexSettings,
+ final Closeable entitlementGrant
) {
- this(prepareEnvironment(settings, configPath), classpathPlugins, forbidPrivateIndexSettings);
+ this(prepareEnvironment(settings, configPath), classpathPlugins, forbidPrivateIndexSettings, entitlementGrant);
}
private MockNode(
final Environment environment,
final Collection> classpathPlugins,
- final boolean forbidPrivateIndexSettings
+ final boolean forbidPrivateIndexSettings,
+ final Closeable entitlementGrant
) {
super(NodeConstruction.prepareConstruction(environment, null, new MockServiceProvider() {
@@ -273,10 +279,10 @@ PluginsService newPluginService(Environment environment, PluginsLoader pluginsLo
}, forbidPrivateIndexSettings));
this.classpathPlugins = classpathPlugins;
+ this.entitlementGrant = entitlementGrant;
}
private static Environment prepareEnvironment(final Settings settings, final Path configPath) {
- TestEntitlementBootstrap.registerNodeBaseDirs(settings, configPath);
return InternalSettingsPreparer.prepareEnvironment(
Settings.builder().put(TransportSettings.PORT.getKey(), ESTestCase.getPortRange()).put(settings).build(),
Collections.emptyMap(),
@@ -286,11 +292,12 @@ private static Environment prepareEnvironment(final Settings settings, final Pat
}
@Override
- public synchronized void close() throws IOException {
+ public synchronized boolean awaitClose(long timeout, TimeUnit timeUnit) throws InterruptedException {
try {
- super.close();
+ return super.awaitClose(timeout, timeUnit);
} finally {
- TestEntitlementBootstrap.unregisterNodeBaseDirs(getEnvironment().settings(), getEnvironment().configDir());
+ // wipePendingDataDirectories requires entitlement delegation to work due to this using FileSystemUtils ES-10920
+ IOUtils.closeWhileHandlingException(entitlementGrant);
}
}
diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractMultiClustersTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractMultiClustersTestCase.java
index b4f91f68b8bb7..2b6abb67b4353 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/AbstractMultiClustersTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractMultiClustersTestCase.java
@@ -127,7 +127,8 @@ public final void startClusters() throws Exception {
0,
clusterName + "-",
mockPlugins,
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
try {
cluster.beforeTest(random());
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
index 89099bb7e32ff..52f99ef8fdd1f 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESIntegTestCase.java
@@ -549,6 +549,7 @@ private TestCluster buildAndPutCluster(Scope currentClusterScope, long seed) thr
// close the previous one and create a new one
if (testCluster != null) {
IOUtils.closeWhileHandlingException(testCluster::close);
+ TEST_ENTITLEMENTS.revokeNodeGrants();
}
testCluster = buildTestCluster(currentClusterScope, seed);
}
@@ -2336,7 +2337,8 @@ protected TestCluster buildTestCluster(Scope scope, long seed) throws IOExceptio
getClientWrapper(),
forbidPrivateIndexSettings(),
forceSingleDataPath(),
- autoManageVotingExclusions()
+ autoManageVotingExclusions(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
}
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
index 7ebc5765bda63..66af9e9c56e61 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESSingleNodeTestCase.java
@@ -288,7 +288,7 @@ private Node newNode() {
plugins.add(ConcurrentSearchTestPlugin.class);
}
plugins.add(MockScriptService.TestPlugin.class);
- Node node = new MockNode(settings, plugins, forbidPrivateIndexSettings());
+ Node node = new MockNode(settings, plugins, forbidPrivateIndexSettings(), TEST_ENTITLEMENTS.newNodeGrant(settings, null));
try {
node.start();
} catch (NodeValidationException e) {
diff --git a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
index 50d78657fbfa1..43243e431db48 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/ESTestCase.java
@@ -111,7 +111,7 @@
import org.elasticsearch.core.SuppressForbidden;
import org.elasticsearch.core.TimeValue;
import org.elasticsearch.core.Tuple;
-import org.elasticsearch.entitlement.bootstrap.TestEntitlementBootstrap;
+import org.elasticsearch.entitlement.bootstrap.TestEntitlementsRule;
import org.elasticsearch.env.Environment;
import org.elasticsearch.env.NodeEnvironment;
import org.elasticsearch.env.TestEnvironment;
@@ -159,6 +159,7 @@
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
+import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.internal.AssumptionViolatedException;
import org.junit.rules.RuleChain;
@@ -524,30 +525,8 @@ protected void afterIfSuccessful() throws Exception {}
String[] value();
}
- @BeforeClass
- public static void setupEntitlementsForClass() {
- boolean withoutEntitlements = getTestClass().isAnnotationPresent(WithoutEntitlements.class);
- boolean withEntitlementsOnTestCode = getTestClass().isAnnotationPresent(WithEntitlementsOnTestCode.class);
- EntitledTestPackages entitledPackages = getTestClass().getAnnotation(EntitledTestPackages.class);
-
- if (TestEntitlementBootstrap.isEnabledForTest()) {
- TestEntitlementBootstrap.setActive(false == withoutEntitlements);
- TestEntitlementBootstrap.setTriviallyAllowingTestCode(false == withEntitlementsOnTestCode);
- if (entitledPackages != null) {
- assert entitledPackages.value().length > 0 : "No test packages specified in @EntitledTestPackages";
- TestEntitlementBootstrap.setEntitledTestPackages(entitledPackages.value());
- }
- } else if (withEntitlementsOnTestCode) {
- throw new AssertionError(
- "Cannot use @WithEntitlementsOnTestCode on tests that are not configured to use entitlements for testing"
- );
- }
- }
-
- @AfterClass
- public static void resetEntitlements() {
- TestEntitlementBootstrap.reset();
- }
+ @ClassRule
+ public static final TestEntitlementsRule TEST_ENTITLEMENTS = new TestEntitlementsRule();
// setup mock filesystems for this test run. we change PathUtils
// so that all accesses are plumbed thru any mock wrappers
diff --git a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java
index cb45797f9b822..0ab12b697801c 100644
--- a/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java
+++ b/test/framework/src/main/java/org/elasticsearch/test/InternalTestCluster.java
@@ -178,6 +178,9 @@
*
*/
public final class InternalTestCluster extends TestCluster {
+ public interface NodeGrantProvider {
+ Closeable create(Settings settings, Path configPath);
+ }
private static final Logger logger = LogManager.getLogger(InternalTestCluster.class);
@@ -278,6 +281,8 @@ public String toString() {
// index of node to bootstrap as master, or BOOTSTRAP_MASTER_NODE_INDEX_AUTO or BOOTSTRAP_MASTER_NODE_INDEX_DONE
private int bootstrapMasterNodeIndex = BOOTSTRAP_MASTER_NODE_INDEX_AUTO;
+ private final NodeGrantProvider nodeGrantProvider;
+
public InternalTestCluster(
final long clusterSeed,
final Path baseDir,
@@ -290,7 +295,8 @@ public InternalTestCluster(
final int numClientNodes,
final String nodePrefix,
final Collection> mockPlugins,
- final Function clientWrapper
+ final Function clientWrapper,
+ NodeGrantProvider nodeGrantProvider
) {
this(
clusterSeed,
@@ -307,7 +313,8 @@ public InternalTestCluster(
clientWrapper,
true,
false,
- true
+ true,
+ nodeGrantProvider
);
}
@@ -326,7 +333,8 @@ public InternalTestCluster(
final Function clientWrapper,
final boolean forbidPrivateIndexSettings,
final boolean forceSingleDataPath,
- final boolean autoManageVotingExclusions
+ final boolean autoManageVotingExclusions,
+ final NodeGrantProvider nodeGrantProvider
) {
super(clusterSeed);
this.autoManageMasterNodes = autoManageMasterNodes;
@@ -335,6 +343,7 @@ public InternalTestCluster(
this.baseDir = baseDir;
this.clusterName = clusterName;
this.autoManageVotingExclusions = autoManageVotingExclusions;
+ this.nodeGrantProvider = nodeGrantProvider;
if (minNumDataNodes < 0 || maxNumDataNodes < 0) {
throw new IllegalArgumentException("minimum and maximum number of data nodes must be >= 0");
}
@@ -783,7 +792,14 @@ private synchronized NodeAndClient buildNode(int nodeId, Settings settings, bool
// we clone this here since in the case of a node restart we might need it again
secureSettings = ((MockSecureSettings) secureSettings).clone();
}
- MockNode node = new MockNode(settings, plugins, nodeConfigurationSource.nodeConfigPath(nodeId), forbidPrivateIndexSettings);
+ Path configPath = nodeConfigurationSource.nodeConfigPath(nodeId);
+ MockNode node = new MockNode(
+ settings,
+ plugins,
+ configPath,
+ forbidPrivateIndexSettings,
+ nodeGrantProvider.create(settings, configPath)
+ );
node.injector().getInstance(TransportService.class).addLifecycleListener(new LifecycleListener() {
@Override
public void afterStart() {
@@ -1058,7 +1074,7 @@ private void recreateNode(final Settings newSettings, final Runnable onTransport
.put(NodeEnvironment.NODE_ID_SEED_SETTING.getKey(), newIdSeed)
.build();
Collection> plugins = node.getClasspathPlugins();
- node = new MockNode(finalSettings, plugins, forbidPrivateIndexSettings);
+ node = new MockNode(finalSettings, plugins, forbidPrivateIndexSettings, nodeGrantProvider.create(finalSettings, null));
node.injector().getInstance(TransportService.class).addLifecycleListener(new LifecycleListener() {
@Override
public void afterStart() {
diff --git a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
index 4a62355f398d8..c0f1aaa227cdb 100644
--- a/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/entitlement/runtime/policy/TestPolicyManagerTests.java
@@ -41,13 +41,13 @@ public void setupPolicyManager() {
policyManager.setActive(true);
}
- public void testReset() {
+ public void testResetAfterTest() {
assertTrue(policyManager.classEntitlementsMap.isEmpty());
assertEquals("example-plugin1", policyManager.getEntitlements(getClass()).componentName());
assertEquals("example-plugin1", policyManager.getEntitlements(getClass()).componentName());
assertFalse(policyManager.classEntitlementsMap.isEmpty());
- policyManager.reset();
+ policyManager.resetAfterTest();
assertTrue(policyManager.classEntitlementsMap.isEmpty());
assertEquals("example-plugin2", policyManager.getEntitlements(getClass()).componentName());
diff --git a/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java b/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java
index f5c358b3b3301..23282572607c0 100644
--- a/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java
+++ b/test/framework/src/test/java/org/elasticsearch/test/test/InternalTestClusterTests.java
@@ -85,7 +85,8 @@ public void testInitializiationIsConsistent() {
numClientNodes,
nodePrefix,
Collections.emptyList(),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
InternalTestCluster cluster1 = new InternalTestCluster(
clusterSeed,
@@ -99,7 +100,8 @@ public void testInitializiationIsConsistent() {
numClientNodes,
nodePrefix,
Collections.emptyList(),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
assertClusters(cluster0, cluster1, true);
}
@@ -198,7 +200,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
numClientNodes,
nodePrefix,
mockPlugins(),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
cluster0.setBootstrapMasterNodeIndex(bootstrapMasterNodeIndex);
@@ -214,7 +217,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
numClientNodes,
nodePrefix,
mockPlugins(),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
cluster1.setBootstrapMasterNodeIndex(bootstrapMasterNodeIndex);
@@ -280,7 +284,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
numClientNodes,
nodePrefix,
mockPlugins(),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
try {
cluster.beforeTest(random());
@@ -375,7 +380,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
0,
"",
mockPlugins(),
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
cluster.beforeTest(random());
List roles = new ArrayList<>();
@@ -467,7 +473,8 @@ public Path nodeConfigPath(int nodeOrdinal) {
0,
nodePrefix,
plugins,
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
try {
cluster.beforeTest(random());
diff --git a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java
index 644a2a074ac59..bd2f53b238ae7 100644
--- a/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java
+++ b/x-pack/plugin/ccr/src/test/java/org/elasticsearch/xpack/CcrIntegTestCase.java
@@ -182,7 +182,8 @@ public final void startClusters() throws Exception {
0,
"leader",
mockPlugins,
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
leaderCluster.beforeTest(random());
leaderCluster.ensureAtLeastNumDataNodes(numberOfNodesPerCluster());
@@ -204,7 +205,8 @@ public final void startClusters() throws Exception {
0,
"follower",
mockPlugins,
- Function.identity()
+ Function.identity(),
+ TEST_ENTITLEMENTS::newNodeGrant
);
clusterGroup = new ClusterGroup(leaderCluster, followerCluster);
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterBasicLicenseIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterBasicLicenseIT.java
index e2d00b8c52781..33b9adb431a0a 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterBasicLicenseIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterBasicLicenseIT.java
@@ -23,6 +23,7 @@
import org.elasticsearch.license.LicenseSettings;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.inference.LocalStateInferencePlugin;
import org.elasticsearch.xpack.inference.Utils;
@@ -42,6 +43,7 @@
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.instanceOf;
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class ShardBulkInferenceActionFilterBasicLicenseIT extends ESIntegTestCase {
public static final String INDEX_NAME = "test-index";
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterIT.java
index 8405fba22460f..7ddbf4fc55ffd 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/action/filter/ShardBulkInferenceActionFilterIT.java
@@ -32,6 +32,7 @@
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.xpack.inference.InferenceIndex;
import org.elasticsearch.xpack.inference.LocalStateInferencePlugin;
@@ -56,6 +57,7 @@
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class ShardBulkInferenceActionFilterIT extends ESIntegTestCase {
public static final String INDEX_NAME = "test-index";
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java
index 1eb530ac1bb9e..a0055332a36c2 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/InferenceRevokeDefaultEndpointsIT.java
@@ -20,6 +20,7 @@
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.reindex.ReindexPlugin;
import org.elasticsearch.test.ESSingleNodeTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.http.MockResponse;
import org.elasticsearch.test.http.MockWebServer;
import org.elasticsearch.threadpool.ThreadPool;
@@ -47,6 +48,7 @@
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.mockito.Mockito.mock;
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class InferenceRevokeDefaultEndpointsIT extends ESSingleNodeTestCase {
private static final TimeValue TIMEOUT = new TimeValue(30, TimeUnit.SECONDS);
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java
index 22aebee72df0c..92eea9599ec5d 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/ModelRegistryIT.java
@@ -35,6 +35,7 @@
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.reindex.ReindexPlugin;
import org.elasticsearch.test.ESSingleNodeTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xcontent.ToXContentObject;
import org.elasticsearch.xcontent.XContentBuilder;
@@ -75,6 +76,7 @@
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class ModelRegistryIT extends ESSingleNodeTestCase {
private static final TimeValue TIMEOUT = new TimeValue(30, TimeUnit.SECONDS);
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java
index 035ec4dc9593d..08d3f0a6a9b9f 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexOptionsIT.java
@@ -30,6 +30,7 @@
import org.elasticsearch.protocol.xpack.license.GetLicenseRequest;
import org.elasticsearch.reindex.ReindexPlugin;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.InternalTestCluster;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xcontent.XContentBuilder;
@@ -55,6 +56,7 @@
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.hamcrest.CoreMatchers.equalTo;
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class SemanticTextIndexOptionsIT extends ESIntegTestCase {
private static final String INDEX_NAME = "test-index";
private static final Map BBQ_COMPATIBLE_SERVICE_SETTINGS = Map.of(
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexVersionIT.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexVersionIT.java
index 6f8992b5bd200..8986b0a158e9f 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexVersionIT.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/integration/SemanticTextIndexVersionIT.java
@@ -24,6 +24,7 @@
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.index.IndexVersionUtils;
import org.elasticsearch.xcontent.XContentBuilder;
import org.elasticsearch.xcontent.XContentFactory;
@@ -50,6 +51,7 @@
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertResponse;
import static org.hamcrest.Matchers.equalTo;
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class SemanticTextIndexVersionIT extends ESIntegTestCase {
private static final int MAXIMUM_NUMBER_OF_VERSIONS_TO_TEST = 25;
private static final String SPARSE_SEMANTIC_FIELD = "sparse_field";
diff --git a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/rest/ServerSentEventsRestActionListenerTests.java b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/rest/ServerSentEventsRestActionListenerTests.java
index 87e14e4e89d88..3287995588d86 100644
--- a/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/rest/ServerSentEventsRestActionListenerTests.java
+++ b/x-pack/plugin/inference/src/internalClusterTest/java/org/elasticsearch/xpack/inference/rest/ServerSentEventsRestActionListenerTests.java
@@ -45,6 +45,7 @@
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.test.ESIntegTestCase;
+import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.xcontent.ToXContent;
import org.elasticsearch.xpack.core.inference.action.InferenceAction;
@@ -75,6 +76,7 @@
import static org.hamcrest.Matchers.nullValue;
@ESIntegTestCase.ClusterScope(numDataNodes = 1)
+@ESTestCase.WithoutEntitlements // due to dependency issue ES-12435
public class ServerSentEventsRestActionListenerTests extends ESIntegTestCase {
private static final String INFERENCE_ROUTE = "/_inference";
private static final String REQUEST_COUNT = "request_count";
diff --git a/x-pack/plugin/searchable-snapshots/src/main/plugin-metadata/entitlement-policy.yaml b/x-pack/plugin/searchable-snapshots/src/main/plugin-metadata/entitlement-policy.yaml
index 69eead6707114..d21ee299b832d 100644
--- a/x-pack/plugin/searchable-snapshots/src/main/plugin-metadata/entitlement-policy.yaml
+++ b/x-pack/plugin/searchable-snapshots/src/main/plugin-metadata/entitlement-policy.yaml
@@ -6,3 +6,6 @@ org.elasticsearch.searchablesnapshots:
- relative_path: indices
relative_to: data
mode: read_write
+ - relative_path: ""
+ relative_to: shared_data
+ mode: read_write