From ae17505557a9951fb9c8a89b9c616b97a5a2c791 Mon Sep 17 00:00:00 2001 From: Nhat Nguyen Date: Wed, 27 Sep 2023 12:45:39 -0700 Subject: [PATCH] Introduce authorization for enrich in ESQL (#99646) This change introduces a new privilege monitor_enrich. Users are required to have this privilege in order to use the enrich functionality in ESQL. Additionally, it eliminates the need to use the enrich_origin when executing enrich lookups. The enrich_origin will only be used when resolving enrich policies to prevent warnings when accessing system indices directly. Closes #98482 --- .../security/get-builtin-privileges.asciidoc | 1 + .../privilege/ClusterPrivilegeResolver.java | 6 +- .../authz/privilege/PrivilegeTests.java | 11 ++ x-pack/plugin/esql/qa/security/build.gradle | 2 + x-pack/plugin/esql/qa/security/roles.yml | 21 +++- .../xpack/esql/EsqlSecurityIT.java | 28 +++-- .../esql/enrich/EnrichLookupService.java | 25 ++--- .../esql/enrich/EnrichPolicyResolver.java | 103 +++++++++++++++--- .../xpack/esql/execution/PlanExecutor.java | 35 +++--- .../xpack/esql/plugin/EsqlPlugin.java | 9 +- .../esql/plugin/TransportEsqlQueryAction.java | 4 + .../esql/stats/PlanExecutorMetricsTests.java | 8 +- .../test/privileges/11_builtin.yml | 2 +- 13 files changed, 186 insertions(+), 69 deletions(-) diff --git a/docs/reference/rest-api/security/get-builtin-privileges.asciidoc b/docs/reference/rest-api/security/get-builtin-privileges.asciidoc index ce7263e4d46f3..8f75293e2c1a4 100644 --- a/docs/reference/rest-api/security/get-builtin-privileges.asciidoc +++ b/docs/reference/rest-api/security/get-builtin-privileges.asciidoc @@ -98,6 +98,7 @@ A successful call returns an object with "cluster" and "index" fields. "manage_watcher", "monitor", "monitor_data_frame_transforms", + "monitor_enrich", "monitor_ml", "monitor_rollup", "monitor_snapshot", diff --git a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java index 9edda8b61739b..68c8491b70528 100644 --- a/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java +++ b/x-pack/plugin/core/src/main/java/org/elasticsearch/xpack/core/security/authz/privilege/ClusterPrivilegeResolver.java @@ -101,6 +101,8 @@ public class ClusterPrivilegeResolver { private static final Set MONITOR_TRANSFORM_PATTERN = Set.of("cluster:monitor/data_frame/*", "cluster:monitor/transform/*"); private static final Set MONITOR_WATCHER_PATTERN = Set.of("cluster:monitor/xpack/watcher/*"); private static final Set MONITOR_ROLLUP_PATTERN = Set.of("cluster:monitor/xpack/rollup/*"); + private static final Set MONITOR_ENRICH_PATTERN = Set.of("cluster:monitor/xpack/enrich/*", "cluster:admin/xpack/enrich/get"); + private static final Set ALL_CLUSTER_PATTERN = Set.of( "cluster:*", "indices:admin/template/*", @@ -172,7 +174,7 @@ public class ClusterPrivilegeResolver { XPackInfoAction.NAME, ClusterStateAction.NAME ); - private static final Set MANAGE_ENRICH_AUTOMATON = Set.of("cluster:admin/xpack/enrich/*"); + private static final Set MANAGE_ENRICH_AUTOMATON = Set.of("cluster:admin/xpack/enrich/*", "cluster:monitor/xpack/enrich/*"); public static final NamedClusterPrivilege NONE = new ActionClusterPrivilege("none", Set.of(), Set.of()); public static final NamedClusterPrivilege ALL = new ActionClusterPrivilege("all", ALL_CLUSTER_PATTERN); @@ -192,6 +194,7 @@ public class ClusterPrivilegeResolver { ); public static final NamedClusterPrivilege MONITOR_WATCHER = new ActionClusterPrivilege("monitor_watcher", MONITOR_WATCHER_PATTERN); public static final NamedClusterPrivilege MONITOR_ROLLUP = new ActionClusterPrivilege("monitor_rollup", MONITOR_ROLLUP_PATTERN); + public static final NamedClusterPrivilege MONITOR_ENRICH = new ActionClusterPrivilege("monitor_enrich", MONITOR_ENRICH_PATTERN); public static final NamedClusterPrivilege MANAGE = new ActionClusterPrivilege("manage", ALL_CLUSTER_PATTERN, ALL_SECURITY_PATTERN); public static final NamedClusterPrivilege MANAGE_ML = new ActionClusterPrivilege("manage_ml", MANAGE_ML_PATTERN); public static final NamedClusterPrivilege MANAGE_TRANSFORM_DEPRECATED = new ActionClusterPrivilege( @@ -333,6 +336,7 @@ public class ClusterPrivilegeResolver { MONITOR_TRANSFORM, MONITOR_WATCHER, MONITOR_ROLLUP, + MONITOR_ENRICH, MANAGE, MANAGE_ML, MANAGE_TRANSFORM_DEPRECATED, diff --git a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java index 1ba478d61943e..59add1cac3539 100644 --- a/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java +++ b/x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/security/authz/privilege/PrivilegeTests.java @@ -379,9 +379,20 @@ public void testManageEnrichPrivilege() { verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, GetEnrichPolicyAction.NAME); verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, PutEnrichPolicyAction.NAME); verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, "cluster:admin/xpack/enrich/brand_new_api"); + verifyClusterActionAllowed(ClusterPrivilegeResolver.MANAGE_ENRICH, "cluster:monitor/xpack/enrich/esql/resolve_policy"); verifyClusterActionDenied(ClusterPrivilegeResolver.MANAGE_ENRICH, "cluster:admin/xpack/whatever"); } + public void testMonitorEnrichPrivilege() { + verifyClusterActionAllowed(ClusterPrivilegeResolver.MONITOR_ENRICH, "cluster:monitor/xpack/enrich/esql/resolve_policy"); + verifyClusterActionAllowed(ClusterPrivilegeResolver.MONITOR_ENRICH, GetEnrichPolicyAction.NAME); + verifyClusterActionAllowed(ClusterPrivilegeResolver.MONITOR_ENRICH, "cluster:monitor/xpack/enrich/brand_new_api"); + verifyClusterActionDenied(ClusterPrivilegeResolver.MONITOR_ENRICH, PutEnrichPolicyAction.NAME); + verifyClusterActionDenied(ClusterPrivilegeResolver.MONITOR_ENRICH, ExecuteEnrichPolicyAction.NAME); + verifyClusterActionDenied(ClusterPrivilegeResolver.MONITOR_ENRICH, DeleteEnrichPolicyAction.NAME); + verifyClusterActionDenied(ClusterPrivilegeResolver.MONITOR_ENRICH, "cluster:admin/xpack/whatever"); + } + public void testIlmPrivileges() { { verifyClusterActionAllowed( diff --git a/x-pack/plugin/esql/qa/security/build.gradle b/x-pack/plugin/esql/qa/security/build.gradle index 4a1b32587da61..44a4f5a27efea 100644 --- a/x-pack/plugin/esql/qa/security/build.gradle +++ b/x-pack/plugin/esql/qa/security/build.gradle @@ -11,4 +11,6 @@ testClusters.configureEach { user username: "user1", password: 'x-pack-test-password', role: "user1" user username: "user2", password: 'x-pack-test-password', role: "user2" user username: "user3", password: 'x-pack-test-password', role: "user3" + user username: "user4", password: 'x-pack-test-password', role: "user4" + user username: "user5", password: 'x-pack-test-password', role: "user5" } diff --git a/x-pack/plugin/esql/qa/security/roles.yml b/x-pack/plugin/esql/qa/security/roles.yml index d18389dc58879..7a89fa57f7102 100644 --- a/x-pack/plugin/esql/qa/security/roles.yml +++ b/x-pack/plugin/esql/qa/security/roles.yml @@ -13,6 +13,7 @@ test-admin: user1: cluster: - cluster:monitor/main + - manage_enrich indices: - names: ['index-user1', 'index', "test-enrich" ] privileges: @@ -22,8 +23,7 @@ user1: - indices:admin/refresh user2: - cluster: - - cluster:monitor/main + cluster: [] indices: - names: [ 'index-user2', 'index' ] privileges: @@ -33,8 +33,7 @@ user2: - indices:admin/refresh user3: - cluster: - - cluster:monitor/main + cluster: [] indices: - names: [ 'index' ] privileges: [ 'read' ] @@ -44,3 +43,17 @@ user3: "org": "sales" } } + +user4: + cluster: + - monitor_enrich + indices: + - names: ['index-user1', 'index', "test-enrich" ] + privileges: + - read +user5: + cluster: [] + indices: + - names: ['index-user1', 'index', "test-enrich" ] + privileges: + - read diff --git a/x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java b/x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java index 3d637e30da4c1..3d0787048685c 100644 --- a/x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java +++ b/x-pack/plugin/esql/qa/security/src/javaRestTest/java/org/elasticsearch/xpack/esql/EsqlSecurityIT.java @@ -7,6 +7,7 @@ package org.elasticsearch.xpack.esql; +import org.apache.http.HttpStatus; import org.elasticsearch.client.Request; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.Response; @@ -152,15 +153,26 @@ record Listen(long timestamp, String songId, double duration) { client().performRequest(indexDoc); } refresh("test-enrich"); - Response resp = runESQLCommand( - "user1", - "FROM test-enrich | ENRICH songs ON song_id | stats total_duration = sum(duration) by artist | sort artist" - ); - Map respMap = entityAsMap(resp); - assertThat( - respMap.get("values"), - equalTo(List.of(List.of(2.75, "Disturbed"), List.of(10.5, "Eagles"), List.of(8.25, "Linkin Park"))) + for (String user : List.of("user1", "user4")) { + Response resp = runESQLCommand( + user, + "FROM test-enrich | ENRICH songs ON song_id | stats total_duration = sum(duration) by artist | sort artist" + ); + Map respMap = entityAsMap(resp); + assertThat( + respMap.get("values"), + equalTo(List.of(List.of(2.75, "Disturbed"), List.of(10.5, "Eagles"), List.of(8.25, "Linkin Park"))) + ); + } + + ResponseException resp = expectThrows( + ResponseException.class, + () -> runESQLCommand( + "user5", + "FROM test-enrich | ENRICH songs ON song_id | stats total_duration = sum(duration) by artist | sort artist" + ) ); + assertThat(resp.getResponse().getStatusLine().getStatusCode(), equalTo(HttpStatus.SC_FORBIDDEN)); } finally { removeEnrichPolicy(); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichLookupService.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichLookupService.java index ba07a688387cc..ca37b498f05ac 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichLookupService.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichLookupService.java @@ -12,7 +12,6 @@ import org.elasticsearch.action.IndicesRequest; import org.elasticsearch.action.UnavailableShardsException; import org.elasticsearch.action.support.ChannelActionListener; -import org.elasticsearch.action.support.ContextPreservingActionListener; import org.elasticsearch.action.support.IndicesOptions; import org.elasticsearch.cluster.ClusterState; import org.elasticsearch.cluster.node.DiscoveryNode; @@ -23,7 +22,6 @@ import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.util.BigArrays; -import org.elasticsearch.common.util.concurrent.ThreadContext; import org.elasticsearch.compute.data.Block; import org.elasticsearch.compute.data.BlockFactory; import org.elasticsearch.compute.data.ElementType; @@ -52,7 +50,6 @@ import org.elasticsearch.transport.TransportRequestOptions; import org.elasticsearch.transport.TransportResponse; import org.elasticsearch.transport.TransportService; -import org.elasticsearch.xpack.core.ClientHelper; import org.elasticsearch.xpack.esql.EsqlIllegalArgumentException; import org.elasticsearch.xpack.esql.action.EsqlQueryAction; import org.elasticsearch.xpack.esql.io.stream.PlanNameRegistry; @@ -141,19 +138,15 @@ public void lookupAsync( } DiscoveryNode targetNode = clusterState.nodes().get(shardRouting.currentNodeId()); LookupRequest lookupRequest = new LookupRequest(sessionId, shardIt.shardId(), matchType, matchField, inputPage, extractFields); - ThreadContext threadContext = transportService.getThreadPool().getThreadContext(); - listener = ContextPreservingActionListener.wrapPreservingContext(listener, threadContext); - try (ThreadContext.StoredContext ignored = threadContext.stashWithOrigin(ClientHelper.ENRICH_ORIGIN)) { - // TODO: handle retry and avoid forking for the local lookup - transportService.sendChildRequest( - targetNode, - LOOKUP_ACTION_NAME, - lookupRequest, - parentTask, - TransportRequestOptions.EMPTY, - new ActionListenerResponseHandler<>(listener.map(r -> r.page), LookupResponse::new, executor) - ); - } + // TODO: handle retry and avoid forking for the local lookup + transportService.sendChildRequest( + targetNode, + LOOKUP_ACTION_NAME, + lookupRequest, + parentTask, + TransportRequestOptions.EMPTY, + new ActionListenerResponseHandler<>(listener.map(r -> r.page), LookupResponse::new, executor) + ); } private void doLookup( diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolver.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolver.java index a2b1d914d1435..cdafee6d76ef0 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolver.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/enrich/EnrichPolicyResolver.java @@ -8,46 +8,123 @@ package org.elasticsearch.xpack.esql.enrich; import org.elasticsearch.action.ActionListener; +import org.elasticsearch.action.ActionListenerResponseHandler; +import org.elasticsearch.action.support.ChannelActionListener; import org.elasticsearch.action.support.ContextPreservingActionListener; import org.elasticsearch.cluster.service.ClusterService; +import org.elasticsearch.common.io.stream.StreamInput; +import org.elasticsearch.common.io.stream.StreamOutput; import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.tasks.Task; import org.elasticsearch.threadpool.ThreadPool; +import org.elasticsearch.transport.TransportChannel; +import org.elasticsearch.transport.TransportRequest; +import org.elasticsearch.transport.TransportRequestHandler; +import org.elasticsearch.transport.TransportResponse; +import org.elasticsearch.transport.TransportService; import org.elasticsearch.xpack.core.ClientHelper; import org.elasticsearch.xpack.core.enrich.EnrichMetadata; import org.elasticsearch.xpack.core.enrich.EnrichPolicy; +import org.elasticsearch.xpack.esql.plugin.EsqlPlugin; import org.elasticsearch.xpack.ql.index.IndexResolver; import java.util.Map; import java.util.Set; public class EnrichPolicyResolver { + private static final String RESOLVE_ACTION_NAME = "cluster:monitor/xpack/enrich/esql/resolve_policy"; private final ClusterService clusterService; private final IndexResolver indexResolver; + private final TransportService transportService; private final ThreadPool threadPool; - public EnrichPolicyResolver(ClusterService clusterService, IndexResolver indexResolver, ThreadPool threadPool) { + public EnrichPolicyResolver(ClusterService clusterService, TransportService transportService, IndexResolver indexResolver) { this.clusterService = clusterService; + this.transportService = transportService; this.indexResolver = indexResolver; - this.threadPool = threadPool; + this.threadPool = transportService.getThreadPool(); + transportService.registerRequestHandler( + RESOLVE_ACTION_NAME, + threadPool.executor(EsqlPlugin.ESQL_THREAD_POOL_NAME), + ResolveRequest::new, + new RequestHandler() + ); } public void resolvePolicy(String policyName, ActionListener listener) { - EnrichPolicy policy = policies().get(policyName); - ThreadContext threadContext = threadPool.getThreadContext(); - listener = ContextPreservingActionListener.wrapPreservingContext(listener, threadContext); - try (ThreadContext.StoredContext ignored = threadContext.stashWithOrigin(ClientHelper.ENRICH_ORIGIN)) { - indexResolver.resolveAsMergedMapping( - EnrichPolicy.getBaseName(policyName), - IndexResolver.ALL_FIELDS, - false, - Map.of(), - listener.map(indexResult -> new EnrichPolicyResolution(policyName, policy, indexResult)) - ); + transportService.sendRequest( + clusterService.localNode(), + RESOLVE_ACTION_NAME, + new ResolveRequest(policyName), + new ActionListenerResponseHandler<>( + listener.map(r -> r.resolution), + ResolveResponse::new, + threadPool.executor(EsqlPlugin.ESQL_THREAD_POOL_NAME) + ) + ); + } + + private static UnsupportedOperationException unsupported() { + return new UnsupportedOperationException("local node transport action"); + } + + private static class ResolveRequest extends TransportRequest { + private final String policyName; + + ResolveRequest(String policyName) { + this.policyName = policyName; + } + + ResolveRequest(StreamInput in) { + throw unsupported(); + } + + @Override + public void writeTo(StreamOutput out) { + throw unsupported(); + } + } + + private static class ResolveResponse extends TransportResponse { + private final EnrichPolicyResolution resolution; + + ResolveResponse(EnrichPolicyResolution resolution) { + this.resolution = resolution; + } + + ResolveResponse(StreamInput in) { + throw unsupported(); + } + + @Override + public void writeTo(StreamOutput out) { + throw unsupported(); + } + } + + private class RequestHandler implements TransportRequestHandler { + @Override + public void messageReceived(ResolveRequest request, TransportChannel channel, Task task) throws Exception { + String policyName = request.policyName; + EnrichPolicy policy = policies().get(policyName); + ThreadContext threadContext = threadPool.getThreadContext(); + ActionListener listener = new ChannelActionListener<>(channel); + listener = ContextPreservingActionListener.wrapPreservingContext(listener, threadContext); + try (ThreadContext.StoredContext ignored = threadContext.stashWithOrigin(ClientHelper.ENRICH_ORIGIN)) { + indexResolver.resolveAsMergedMapping( + EnrichPolicy.getBaseName(policyName), + IndexResolver.ALL_FIELDS, + false, + Map.of(), + listener.map(indexResult -> new ResolveResponse(new EnrichPolicyResolution(policyName, policy, indexResult))) + ); + } } } public Set allPolicyNames() { + // TODO: remove this suggestion as it exposes policy names without the right permission return policies().keySet(); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/execution/PlanExecutor.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/execution/PlanExecutor.java index 798927d2c9329..eaf148c27c3ee 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/execution/PlanExecutor.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/execution/PlanExecutor.java @@ -28,7 +28,6 @@ public class PlanExecutor { private final IndexResolver indexResolver; - private final EnrichPolicyResolver enrichPolicyResolver; private final PreAnalyzer preAnalyzer; private final FunctionRegistry functionRegistry; private final LogicalPlanOptimizer logicalPlanOptimizer; @@ -36,9 +35,8 @@ public class PlanExecutor { private final Metrics metrics; private final Verifier verifier; - public PlanExecutor(IndexResolver indexResolver, EnrichPolicyResolver enrichPolicyResolver) { + public PlanExecutor(IndexResolver indexResolver) { this.indexResolver = indexResolver; - this.enrichPolicyResolver = enrichPolicyResolver; this.preAnalyzer = new PreAnalyzer(); this.functionRegistry = new EsqlFunctionRegistry(); this.logicalPlanOptimizer = new LogicalPlanOptimizer(); @@ -47,18 +45,14 @@ public PlanExecutor(IndexResolver indexResolver, EnrichPolicyResolver enrichPoli this.verifier = new Verifier(metrics); } - public void esql(EsqlQueryRequest request, String sessionId, EsqlConfiguration cfg, ActionListener listener) { - QueryMetric clientId = QueryMetric.fromString("rest"); - metrics.total(clientId); - newSession(sessionId, cfg).execute(request, wrap(listener::onResponse, ex -> { - // TODO when we decide if we will differentiate Kibana from REST, this String value will likely come from the request - metrics.failed(clientId); - listener.onFailure(ex); - })); - } - - private EsqlSession newSession(String sessionId, EsqlConfiguration cfg) { - return new EsqlSession( + public void esql( + EsqlQueryRequest request, + String sessionId, + EsqlConfiguration cfg, + EnrichPolicyResolver enrichPolicyResolver, + ActionListener listener + ) { + final var session = new EsqlSession( sessionId, cfg, indexResolver, @@ -69,6 +63,17 @@ private EsqlSession newSession(String sessionId, EsqlConfiguration cfg) { mapper, verifier ); + QueryMetric clientId = QueryMetric.fromString("rest"); + metrics.total(clientId); + session.execute(request, wrap(listener::onResponse, ex -> { + // TODO when we decide if we will differentiate Kibana from REST, this String value will likely come from the request + metrics.failed(clientId); + listener.onFailure(ex); + })); + } + + public IndexResolver indexResolver() { + return indexResolver; } public Metrics metrics() { diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java index 909c6c12893ab..62a74e5023773 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/EsqlPlugin.java @@ -51,7 +51,6 @@ import org.elasticsearch.xpack.esql.EsqlUsageTransportAction; import org.elasticsearch.xpack.esql.action.EsqlQueryAction; import org.elasticsearch.xpack.esql.action.RestEsqlQueryAction; -import org.elasticsearch.xpack.esql.enrich.EnrichPolicyResolver; import org.elasticsearch.xpack.esql.execution.PlanExecutor; import org.elasticsearch.xpack.esql.querydsl.query.SingleValueQuery; import org.elasticsearch.xpack.esql.type.EsqlDataTypeRegistry; @@ -101,14 +100,8 @@ public Collection createComponents( AllocationService allocationService, IndicesService indicesService ) { - IndexResolver indexResolver = new IndexResolver( - client, - clusterService.getClusterName().value(), - EsqlDataTypeRegistry.INSTANCE, - Set::of - ); return List.of( - new PlanExecutor(indexResolver, new EnrichPolicyResolver(clusterService, indexResolver, threadPool)), + new PlanExecutor(new IndexResolver(client, clusterService.getClusterName().value(), EsqlDataTypeRegistry.INSTANCE, Set::of)), new ExchangeService(clusterService.getSettings(), threadPool, EsqlPlugin.ESQL_THREAD_POOL_NAME) ); } diff --git a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java index edfae0f91297d..1ff00401029cf 100644 --- a/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java +++ b/x-pack/plugin/esql/src/main/java/org/elasticsearch/xpack/esql/plugin/TransportEsqlQueryAction.java @@ -29,6 +29,7 @@ import org.elasticsearch.xpack.esql.action.EsqlQueryRequest; import org.elasticsearch.xpack.esql.action.EsqlQueryResponse; import org.elasticsearch.xpack.esql.enrich.EnrichLookupService; +import org.elasticsearch.xpack.esql.enrich.EnrichPolicyResolver; import org.elasticsearch.xpack.esql.execution.PlanExecutor; import org.elasticsearch.xpack.esql.session.EsqlConfiguration; import org.elasticsearch.xpack.esql.type.EsqlDataTypes; @@ -45,6 +46,7 @@ public class TransportEsqlQueryAction extends HandledTransportAction computeService.execute( sessionId, diff --git a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java index 87aea66d1eeb7..95a6389af7fc5 100644 --- a/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java +++ b/x-pack/plugin/esql/src/test/java/org/elasticsearch/xpack/esql/stats/PlanExecutorMetricsTests.java @@ -55,8 +55,10 @@ public void shutdownThreadPool() throws Exception { public void testFailedMetric() { Client client = mock(Client.class); IndexResolver idxResolver = new IndexResolver(client, randomAlphaOfLength(10), EsqlDataTypeRegistry.INSTANCE, Set::of); - var planExecutor = new PlanExecutor(idxResolver, new EnrichPolicyResolver(null, idxResolver, threadPool)); + var planExecutor = new PlanExecutor(idxResolver); String[] indices = new String[] { "test" }; + EnrichPolicyResolver enrichResolver = mock(EnrichPolicyResolver.class); + when(enrichResolver.allPolicyNames()).thenReturn(Set.of()); // simulate a valid field_caps response so we can parse and correctly analyze de query FieldCapabilitiesResponse fieldCapabilitiesResponse = mock(FieldCapabilitiesResponse.class); @@ -72,7 +74,7 @@ public void testFailedMetric() { var request = new EsqlQueryRequest(); // test a failed query: xyz field doesn't exist request.query("from test | stats m = max(xyz)"); - planExecutor.esql(request, randomAlphaOfLength(10), EsqlTestUtils.TEST_CFG, new ActionListener() { + planExecutor.esql(request, randomAlphaOfLength(10), EsqlTestUtils.TEST_CFG, enrichResolver, new ActionListener<>() { @Override public void onResponse(PhysicalPlan physicalPlan) { fail("this shouldn't happen"); @@ -91,7 +93,7 @@ public void onFailure(Exception e) { // fix the failing query: foo field does exist request.query("from test | stats m = max(foo)"); - planExecutor.esql(request, randomAlphaOfLength(10), EsqlTestUtils.TEST_CFG, new ActionListener() { + planExecutor.esql(request, randomAlphaOfLength(10), EsqlTestUtils.TEST_CFG, enrichResolver, new ActionListener<>() { @Override public void onResponse(PhysicalPlan physicalPlan) {} diff --git a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/privileges/11_builtin.yml b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/privileges/11_builtin.yml index 8ec89e5a4c99c..e2e220aa55456 100644 --- a/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/privileges/11_builtin.yml +++ b/x-pack/plugin/src/yamlRestTest/resources/rest-api-spec/test/privileges/11_builtin.yml @@ -15,5 +15,5 @@ setup: # This is fragile - it needs to be updated every time we add a new cluster/index privilege # I would much prefer we could just check that specific entries are in the array, but we don't have # an assertion for that - - length: { "cluster" : 52 } + - length: { "cluster" : 53 } - length: { "index" : 22 }