Skip to content

Commit 1f397e0

Browse files
authored
Merge branch 'main' into skip-un-execution
2 parents 99cc226 + 0698d73 commit 1f397e0

File tree

20 files changed

+569
-53
lines changed

20 files changed

+569
-53
lines changed

docs/changelog/120852.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 120852
2+
summary: Correct line and column numbers of missing named parameters
3+
area: ES|QL
4+
type: bug
5+
issues: []

docs/changelog/121324.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 121324
2+
summary: Support duplicate suggestions in completion field
3+
area: Suggesters
4+
type: bug
5+
issues:
6+
- 82432
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*
2+
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
3+
* or more contributor license agreements. Licensed under the "Elastic License
4+
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
5+
* Public License v 1"; you may not use this file except in compliance with, at
6+
* your election, the "Elastic License 2.0", the "GNU Affero General Public
7+
* License v3.0 only", or the "Server Side Public License, v 1".
8+
*/
9+
10+
package org.elasticsearch.core;
11+
12+
/**
13+
* A {@link java.util.function.Supplier}-like interface which allows throwing checked exceptions.
14+
*/
15+
@FunctionalInterface
16+
public interface CheckedSupplier<T, E extends Exception> {
17+
T get() throws E;
18+
}

libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/DummyImplementations.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,9 @@
5252
* <p>
5353
* A bit like Mockito but way more painful.
5454
*/
55-
class DummyImplementations {
56-
57-
static class DummyLocaleServiceProvider extends LocaleServiceProvider {
55+
public class DummyImplementations {
5856

57+
public static class DummyLocaleServiceProvider extends LocaleServiceProvider {
5958
@Override
6059
public Locale[] getAvailableLocales() {
6160
throw unexpected();

libs/entitlement/qa/entitlement-test-plugin/src/main/java/org/elasticsearch/entitlement/qa/test/RestEntitlementsCheckAction.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,9 @@ static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {
9696

9797
private static final Map<String, CheckAction> checkActions = Stream.concat(
9898
Stream.<Entry<String, CheckAction>>of(
99+
entry("static_reflection", deniedToPlugins(RestEntitlementsCheckAction::staticMethodNeverEntitledViaReflection)),
100+
entry("nonstatic_reflection", deniedToPlugins(RestEntitlementsCheckAction::nonstaticMethodNeverEntitledViaReflection)),
101+
entry("constructor_reflection", deniedToPlugins(RestEntitlementsCheckAction::constructorNeverEntitledViaReflection)),
99102
entry("runtime_exit", deniedToPlugins(RestEntitlementsCheckAction::runtimeExit)),
100103
entry("runtime_halt", deniedToPlugins(RestEntitlementsCheckAction::runtimeHalt)),
101104
entry("system_exit", deniedToPlugins(RestEntitlementsCheckAction::systemExit)),
@@ -338,6 +341,11 @@ private static void systemExit() {
338341
System.exit(123);
339342
}
340343

344+
private static void staticMethodNeverEntitledViaReflection() throws Exception {
345+
Method systemExit = System.class.getMethod("exit", int.class);
346+
systemExit.invoke(null, 123);
347+
}
348+
341349
private static void createClassLoader() throws IOException {
342350
try (var classLoader = new URLClassLoader("test", new URL[0], RestEntitlementsCheckAction.class.getClassLoader())) {
343351
logger.info("Created URLClassLoader [{}]", classLoader.getName());
@@ -348,6 +356,11 @@ private static void processBuilder_start() throws IOException {
348356
new ProcessBuilder("").start();
349357
}
350358

359+
private static void nonstaticMethodNeverEntitledViaReflection() throws Exception {
360+
Method processBuilderStart = ProcessBuilder.class.getMethod("start");
361+
processBuilderStart.invoke(new ProcessBuilder(""));
362+
}
363+
351364
private static void processBuilder_startPipeline() throws IOException {
352365
ProcessBuilder.startPipeline(List.of());
353366
}
@@ -386,6 +399,10 @@ private static void setHttpsConnectionProperties() {
386399
new DummyLocaleServiceProvider();
387400
}
388401

402+
private static void constructorNeverEntitledViaReflection() throws Exception {
403+
DummyLocaleServiceProvider.class.getConstructor().newInstance();
404+
}
405+
389406
private static void breakIteratorProvider$() {
390407
new DummyBreakIteratorProvider();
391408
}

libs/entitlement/src/main/java/org/elasticsearch/entitlement/bootstrap/EntitlementBootstrap.java

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import com.sun.tools.attach.AttachNotSupportedException;
1515
import com.sun.tools.attach.VirtualMachine;
1616

17+
import org.elasticsearch.core.CheckedConsumer;
18+
import org.elasticsearch.core.CheckedSupplier;
1719
import org.elasticsearch.core.SuppressForbidden;
1820
import org.elasticsearch.entitlement.initialization.EntitlementInitialization;
1921
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
@@ -22,8 +24,10 @@
2224
import org.elasticsearch.logging.Logger;
2325

2426
import java.io.IOException;
27+
import java.lang.reflect.InvocationTargetException;
2528
import java.nio.file.Files;
2629
import java.nio.file.Path;
30+
import java.nio.file.attribute.FileAttribute;
2731
import java.util.Map;
2832
import java.util.function.Function;
2933

@@ -144,30 +148,31 @@ private static String findAgentJar() {
144148
* @throws IllegalStateException if the entitlements system can't prevent an unauthorized action of our choosing
145149
*/
146150
private static void selfTest() {
147-
ensureCannotStartProcess();
148-
ensureCanCreateTempFile();
151+
ensureCannotStartProcess(ProcessBuilder::start);
152+
ensureCanCreateTempFile(EntitlementBootstrap::createTempFile);
153+
154+
// Try again with reflection
155+
ensureCannotStartProcess(EntitlementBootstrap::reflectiveStartProcess);
156+
ensureCanCreateTempFile(EntitlementBootstrap::reflectiveCreateTempFile);
149157
}
150158

151-
private static void ensureCannotStartProcess() {
159+
private static void ensureCannotStartProcess(CheckedConsumer<ProcessBuilder, ?> startProcess) {
152160
try {
153161
// The command doesn't matter; it doesn't even need to exist
154-
new ProcessBuilder("").start();
162+
startProcess.accept(new ProcessBuilder(""));
155163
} catch (NotEntitledException e) {
156164
logger.debug("Success: Entitlement protection correctly prevented process creation");
157165
return;
158-
} catch (IOException e) {
166+
} catch (Exception e) {
159167
throw new IllegalStateException("Failed entitlement protection self-test", e);
160168
}
161169
throw new IllegalStateException("Entitlement protection self-test was incorrectly permitted");
162170
}
163171

164-
/**
165-
* Originally {@code Security.selfTest}.
166-
*/
167172
@SuppressForbidden(reason = "accesses jvm default tempdir as a self-test")
168-
private static void ensureCanCreateTempFile() {
173+
private static void ensureCanCreateTempFile(CheckedSupplier<Path, ?> createTempFile) {
169174
try {
170-
Path p = Files.createTempFile(null, null);
175+
Path p = createTempFile.get();
171176
p.toFile().deleteOnExit();
172177

173178
// Make an effort to clean up the file immediately; also, deleteOnExit leaves the file if the JVM exits abnormally.
@@ -184,5 +189,24 @@ private static void ensureCanCreateTempFile() {
184189
logger.debug("Success: Entitlement protection correctly permitted temp file creation");
185190
}
186191

192+
@SuppressForbidden(reason = "accesses jvm default tempdir as a self-test")
193+
private static Path createTempFile() throws Exception {
194+
return Files.createTempFile(null, null);
195+
}
196+
197+
private static void reflectiveStartProcess(ProcessBuilder pb) throws Exception {
198+
try {
199+
var start = ProcessBuilder.class.getMethod("start");
200+
start.invoke(pb);
201+
} catch (InvocationTargetException e) {
202+
throw (Exception) e.getCause();
203+
}
204+
}
205+
206+
private static Path reflectiveCreateTempFile() throws Exception {
207+
return (Path) Files.class.getMethod("createTempFile", String.class, String.class, FileAttribute[].class)
208+
.invoke(null, null, null, new FileAttribute<?>[0]);
209+
}
210+
187211
private static final Logger logger = LogManager.getLogger(EntitlementBootstrap.class);
188212
}

rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/suggest/30_context.yml

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,3 +395,75 @@ setup:
395395
field: suggest_multi_contexts
396396
contexts:
397397
location: []
398+
399+
---
400+
"Duplicate suggestions in different contexts":
401+
- requires:
402+
cluster_features: [ "search.completion_field.duplicate.support" ]
403+
reason: "Support for duplicate suggestions in different contexts"
404+
405+
- do:
406+
index:
407+
refresh: true
408+
index: test
409+
id: "1"
410+
body:
411+
suggest_context:
412+
-
413+
input: "foox"
414+
weight: 2
415+
contexts:
416+
color: ["red", "yellow"]
417+
-
418+
input: "foox"
419+
weight: 3
420+
contexts:
421+
color: ["blue", "green", "yellow"]
422+
- do:
423+
search:
424+
body:
425+
suggest:
426+
result:
427+
text: "foo"
428+
completion:
429+
field: suggest_context
430+
contexts:
431+
color: "red"
432+
433+
- length: { suggest.result: 1 }
434+
- length: { suggest.result.0.options: 1 }
435+
- match: { suggest.result.0.options.0.text: "foox" }
436+
- match: { suggest.result.0.options.0._score: 2 }
437+
438+
- do:
439+
search:
440+
body:
441+
suggest:
442+
result:
443+
text: "foo"
444+
completion:
445+
field: suggest_context
446+
contexts:
447+
color: "yellow"
448+
449+
- length: { suggest.result: 1 }
450+
- length: { suggest.result.0.options: 1 }
451+
- match: { suggest.result.0.options.0.text: "foox" }
452+
# the highest weight wins
453+
- match: { suggest.result.0.options.0._score: 3 }
454+
455+
- do:
456+
search:
457+
body:
458+
suggest:
459+
result:
460+
text: "foo"
461+
completion:
462+
field: suggest_context
463+
contexts:
464+
color: "blue"
465+
466+
- length: { suggest.result: 1 }
467+
- length: { suggest.result.0.options: 1 }
468+
- match: { suggest.result.0.options.0.text: "foox" }
469+
- match: { suggest.result.0.options.0._score: 3 }

rest-api-spec/src/yamlRestTest/resources/rest-api-spec/test/suggest/50_completion_with_multi_fields.yml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,3 +268,80 @@
268268

269269
- length: { suggest.result: 1 }
270270
- length: { suggest.result.0.options: 1 }
271+
272+
---
273+
"Duplicate suggestions in different contexts in sub-fields":
274+
- requires:
275+
cluster_features: [ "search.completion_field.duplicate.support" ]
276+
reason: "Support for duplicate suggestions in different contexts"
277+
278+
- do:
279+
indices.create:
280+
index: completion_with_context
281+
body:
282+
mappings:
283+
"properties":
284+
"suggest_1":
285+
"type": "completion"
286+
"contexts":
287+
-
288+
"name": "color"
289+
"type": "category"
290+
"fields":
291+
"suggest_2":
292+
"type": "completion"
293+
"contexts":
294+
-
295+
"name": "color"
296+
"type": "category"
297+
298+
299+
- do:
300+
index:
301+
refresh: true
302+
index: completion_with_context
303+
id: "1"
304+
body:
305+
suggest_1:
306+
-
307+
input: "foox"
308+
weight: 2
309+
contexts:
310+
color: ["red"]
311+
-
312+
input: "foox"
313+
weight: 3
314+
contexts:
315+
color: ["blue", "green"]
316+
- do:
317+
search:
318+
body:
319+
suggest:
320+
result:
321+
text: "foo"
322+
completion:
323+
field: suggest_1.suggest_2
324+
contexts:
325+
color: "red"
326+
327+
- length: { suggest.result: 1 }
328+
- length: { suggest.result.0.options: 1 }
329+
- match: { suggest.result.0.options.0.text: "foox" }
330+
- match: { suggest.result.0.options.0._score: 2 }
331+
332+
333+
- do:
334+
search:
335+
body:
336+
suggest:
337+
result:
338+
text: "foo"
339+
completion:
340+
field: suggest_1.suggest_2
341+
contexts:
342+
color: "blue"
343+
344+
- length: { suggest.result: 1 }
345+
- length: { suggest.result.0.options: 1 }
346+
- match: { suggest.result.0.options.0.text: "foox" }
347+
- match: { suggest.result.0.options.0._score: 3 }

0 commit comments

Comments
 (0)