From eafa3a3004ceef0e2ae858e0b406fe89bc0ae656 Mon Sep 17 00:00:00 2001 From: Sam Xiao Date: Wed, 25 Feb 2026 15:29:14 -0500 Subject: [PATCH 1/2] Add description to reindex API with sensitive info redacted --- modules/reindex-management/build.gradle | 1 + .../reindex/management/ReindexRemoteIT.java | 94 ++++++++++ .../management/GetReindexResponse.java | 11 +- .../management/GetReindexResponseTests.java | 174 ++++++++++++++++++ .../test/reindex/10_get_reindex.yml | 1 + .../test/reindex/20_list_reindex.yml | 1 + .../test/reindex/30_cancel_reindex.yml | 1 + 7 files changed, 282 insertions(+), 1 deletion(-) create mode 100644 modules/reindex-management/src/javaRestTest/java/org/elasticsearch/reindex/management/ReindexRemoteIT.java create mode 100644 modules/reindex-management/src/test/java/org/elasticsearch/reindex/management/GetReindexResponseTests.java diff --git a/modules/reindex-management/build.gradle b/modules/reindex-management/build.gradle index 040df16bcd30d..40d5bf957fe16 100644 --- a/modules/reindex-management/build.gradle +++ b/modules/reindex-management/build.gradle @@ -10,6 +10,7 @@ apply plugin: 'elasticsearch.internal-cluster-test' apply plugin: 'elasticsearch.internal-yaml-rest-test' apply plugin: 'elasticsearch.yaml-rest-compat-test' +apply plugin: 'elasticsearch.internal-java-rest-test' esplugin { name = 'reindex-management' diff --git a/modules/reindex-management/src/javaRestTest/java/org/elasticsearch/reindex/management/ReindexRemoteIT.java b/modules/reindex-management/src/javaRestTest/java/org/elasticsearch/reindex/management/ReindexRemoteIT.java new file mode 100644 index 0000000000000..15ed4014996f9 --- /dev/null +++ b/modules/reindex-management/src/javaRestTest/java/org/elasticsearch/reindex/management/ReindexRemoteIT.java @@ -0,0 +1,94 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v 3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.reindex.management; + +import org.elasticsearch.client.Request; +import org.elasticsearch.client.Response; +import org.elasticsearch.test.cluster.ElasticsearchCluster; +import org.elasticsearch.test.rest.ESRestTestCase; +import org.junit.ClassRule; + +import java.net.URI; +import java.util.Map; + +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; + +public class ReindexRemoteIT extends ESRestTestCase { + + @ClassRule + public static ElasticsearchCluster cluster = ElasticsearchCluster.local() + .module("reindex") + .module("reindex-management") + .module("rest-root") + .setting("reindex.remote.whitelist", "127.0.0.1:*") + .build(); + + @Override + protected String getTestRestCluster() { + return cluster.getHttpAddresses(); + } + + @SuppressWarnings("unchecked") + private String getRemoteHost() throws Exception { + Map nodesInfo = entityAsMap(client().performRequest(new Request("GET", "/_nodes/http"))); + Map nodes = (Map) nodesInfo.get("nodes"); + Map nodeInfo = (Map) nodes.values().iterator().next(); + Map http = (Map) nodeInfo.get("http"); + return "http://" + http.get("publish_address"); + } + + public void testGetReindexDescriptionStripsRemoteInfoSensitiveFields() throws Exception { + Request indexRequest = new Request("POST", "/remote_src/_doc"); + indexRequest.addParameter("refresh", "true"); + indexRequest.setJsonEntity("{\"field\": \"value\"}"); + client().performRequest(indexRequest); + + String remoteHost = getRemoteHost(); + + Request reindexRequest = new Request("POST", "/_reindex"); + reindexRequest.addParameter("wait_for_completion", "false"); + reindexRequest.setJsonEntity(String.format(java.util.Locale.ROOT, """ + { + "source": { + "remote": { + "host": "%s", + "username": "testuser", + "password": "testpass" + }, + "index": "remote_src", + "query": { + "match_all": {} + } + }, + "dest": { + "index": "dest" + } + }""", remoteHost)); + + Response reindexResponse = client().performRequest(reindexRequest); + String taskId = (String) entityAsMap(reindexResponse).get("task"); + assertNotNull("reindex did not return a task id", taskId); + + Request getReindexRequest = new Request("GET", "/_reindex/" + taskId); + getReindexRequest.addParameter("wait_for_completion", "true"); + Response getResponse = client().performRequest(getReindexRequest); + Map body = entityAsMap(getResponse); + + assertThat(body.get("completed"), is(true)); + URI remoteUri = URI.create(remoteHost); + String expectedDescription = "reindex from [host=" + + remoteUri.getHost() + + " port=" + + remoteUri.getPort() + + "][remote_src] to [dest]"; + assertThat(body.get("description"), equalTo(expectedDescription)); + } +} diff --git a/modules/reindex-management/src/main/java/org/elasticsearch/reindex/management/GetReindexResponse.java b/modules/reindex-management/src/main/java/org/elasticsearch/reindex/management/GetReindexResponse.java index 937678552f8ea..7f5058b0eae26 100644 --- a/modules/reindex-management/src/main/java/org/elasticsearch/reindex/management/GetReindexResponse.java +++ b/modules/reindex-management/src/main/java/org/elasticsearch/reindex/management/GetReindexResponse.java @@ -21,6 +21,7 @@ import java.io.IOException; import java.util.Objects; +import java.util.regex.Pattern; import static java.util.Objects.requireNonNull; @@ -28,6 +29,8 @@ public class GetReindexResponse extends ActionResponse implements ToXContentObje private final TaskResult task; + private static final Pattern DESCRIPTION_FILTER_PATTERN = Pattern.compile("(?s) query=.*?(?=\\]\\[[^\\]]*\\] to \\[)"); + public GetReindexResponse(TaskResult task) { this.task = requireNonNull(task, "task is required"); } @@ -66,8 +69,10 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws // reindex specific TaskInfo serialization static XContentBuilder taskInfoToXContent(XContentBuilder builder, Params params, TaskInfo taskInfo) throws IOException { - // TODO: revisit if we should expose taskInfo.description, since it may contain sensitive information like ip and username builder.field("id", taskInfo.node() + ":" + taskInfo.id()); + if (taskInfo.description() != null) { + builder.field("description", sanitizeDescription(taskInfo.description())); + } builder.timestampFieldsFromUnixEpochMillis("start_time_in_millis", "start_time", taskInfo.startTime()); if (builder.humanReadable()) { builder.field("running_time", TimeValue.timeValueNanos(taskInfo.runningTimeNanos()).toString()); @@ -81,6 +86,10 @@ static XContentBuilder taskInfoToXContent(XContentBuilder builder, Params params return builder; } + static String sanitizeDescription(String description) { + return DESCRIPTION_FILTER_PATTERN.matcher(description).replaceAll(""); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/modules/reindex-management/src/test/java/org/elasticsearch/reindex/management/GetReindexResponseTests.java b/modules/reindex-management/src/test/java/org/elasticsearch/reindex/management/GetReindexResponseTests.java new file mode 100644 index 0000000000000..e786e79f9c73b --- /dev/null +++ b/modules/reindex-management/src/test/java/org/elasticsearch/reindex/management/GetReindexResponseTests.java @@ -0,0 +1,174 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v 3.0 only", or the "Server Side Public License, v 1". + */ + +package org.elasticsearch.reindex.management; + +import org.elasticsearch.test.ESTestCase; + +import static org.elasticsearch.reindex.management.GetReindexResponse.sanitizeDescription; +import static org.hamcrest.Matchers.equalTo; + +public class GetReindexResponseTests extends ESTestCase { + + public void testSanitizeDescriptionLocalReindex() { + assertThat(sanitizeDescription("reindex from [source] to [dest]"), equalTo("reindex from [source] to [dest]")); + } + + public void testSanitizeDescriptionLocalReindexMultipleIndices() { + assertThat(sanitizeDescription("reindex from [source1, source2] to [dest]"), equalTo("reindex from [source1, source2] to [dest]")); + } + + public void testSanitizeDescriptionRemoteWithAllFields() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=real_user password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionRemoteQueryOnly() { + assertThat( + sanitizeDescription("reindex from [host=example.com port=9200 query={\"match_all\":{}}][source] to [dest]"), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionRemoteUsernameOnly() { + assertThat( + sanitizeDescription("reindex from [host=example.com port=9200 query={\"match_all\":{}} username=real_user][source] to [dest]"), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionRemoteWithSchemeAndPathPrefix() { + assertThat( + sanitizeDescription( + "reindex from [scheme=https host=example.com port=9200 pathPrefix=/es query={\"match_all\":{}}" + + " username=real_user password=<<>>][source] to [dest]" + ), + equalTo("reindex from [scheme=https host=example.com port=9200 pathPrefix=/es][source] to [dest]") + ); + } + + public void testSanitizeDescriptionQueryWithPrettyPrintedJson() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\n \"match_all\" : {\n \"boost\" : 1.0\n }\n}" + + " username=real_user password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionQueryWithArrayBrackets() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"terms\":{\"status\":[\"active\",\"pending\"]}}" + + " username=real_user password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionQueryWithNestedArrayBrackets() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"bool\":{\"should\":[{\"terms\":{\"x\":[\"a\",\"b\"]}}," + + "{\"terms\":{\"y\":[\"c\"]}}]}} username=real_user password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionQueryWithLuceneRangeSyntax() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"query_string\":{\"query\":\"field:[1 TO 10]\"}}][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionQueryContainingUsernameEquals() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"query_string\":{\"query\":\" username=admin\"}}" + + " username=real_user password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionQueryContainingPasswordEquals() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"query_string\":{\"query\":\" password=secret\"}}" + + " username=real_user password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionQueryContainingUsernameFieldName() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"term\":{\"username\":\"john\"}}" + + " username=real_user password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionQueryContainingBracketPair() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"query_string\":{\"query\":\"a][b\"}}" + + " username=real_user][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionUsernameWithBrackets() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"match_all\":{}}" + " username=user]name password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionUsernameWithBracketPair() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=user][name password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionUsernameWithSpecialChars() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=user@domain[0] password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } + + public void testSanitizeDescriptionUsernameWithWhitespace() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=user name password=<<>>][source] to [dest]" + ), + equalTo("reindex from [host=example.com port=9200][source] to [dest]") + ); + } +} diff --git a/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/10_get_reindex.yml b/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/10_get_reindex.yml index 73df6a08b774e..afd3291fb51e7 100644 --- a/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/10_get_reindex.yml +++ b/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/10_get_reindex.yml @@ -34,6 +34,7 @@ setup: human: true - is_true: completed - match: { id: $taskId } + - match: { description: "reindex from [source] to [dest]" } - match: { cancelled: false } - exists: start_time - exists: start_time_in_millis diff --git a/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/20_list_reindex.yml b/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/20_list_reindex.yml index 6e223274ebd82..6381549dc9883 100644 --- a/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/20_list_reindex.yml +++ b/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/20_list_reindex.yml @@ -79,6 +79,7 @@ setup: - is_true: reindex - length: { reindex: 1 } - match: { reindex.0.id: $taskId } + - match: { reindex.0.description: "reindex from [source] to [dest]" } - match: { reindex.0.cancelled: false } - exists: reindex.0.start_time - exists: reindex.0.start_time_in_millis diff --git a/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/30_cancel_reindex.yml b/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/30_cancel_reindex.yml index fe02bdd3ae190..22d293ad7760d 100644 --- a/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/30_cancel_reindex.yml +++ b/modules/reindex-management/src/yamlRestTest/resources/rest-api-spec/test/reindex/30_cancel_reindex.yml @@ -46,6 +46,7 @@ setup: human: true - match: { completed: true } - exists: id + - match: { description: "reindex from [source] to [dest]" } - exists: start_time - gte: { start_time_in_millis: 0 } - exists: running_time From 74842987394aa5644e5652829fca69b7b8f5af1e Mon Sep 17 00:00:00 2001 From: Sam Xiao Date: Mon, 2 Mar 2026 20:17:00 -0500 Subject: [PATCH 2/2] address comment --- .../reindex/management/ReindexRemoteIT.java | 3 + .../management/GetReindexResponse.java | 40 ++++++++-- .../management/GetReindexResponseTests.java | 74 ++++++++++++++----- 3 files changed, 94 insertions(+), 23 deletions(-) diff --git a/modules/reindex-management/src/javaRestTest/java/org/elasticsearch/reindex/management/ReindexRemoteIT.java b/modules/reindex-management/src/javaRestTest/java/org/elasticsearch/reindex/management/ReindexRemoteIT.java index 15ed4014996f9..269563a30a0fa 100644 --- a/modules/reindex-management/src/javaRestTest/java/org/elasticsearch/reindex/management/ReindexRemoteIT.java +++ b/modules/reindex-management/src/javaRestTest/java/org/elasticsearch/reindex/management/ReindexRemoteIT.java @@ -70,6 +70,9 @@ public void testGetReindexDescriptionStripsRemoteInfoSensitiveFields() throws Ex }, "dest": { "index": "dest" + }, + "script": { + "source": "ctx._source.tag = 'host=localhost port=9200 username=admin password=secret'" } }""", remoteHost)); diff --git a/modules/reindex-management/src/main/java/org/elasticsearch/reindex/management/GetReindexResponse.java b/modules/reindex-management/src/main/java/org/elasticsearch/reindex/management/GetReindexResponse.java index 7f5058b0eae26..e986b7b5f1177 100644 --- a/modules/reindex-management/src/main/java/org/elasticsearch/reindex/management/GetReindexResponse.java +++ b/modules/reindex-management/src/main/java/org/elasticsearch/reindex/management/GetReindexResponse.java @@ -21,6 +21,8 @@ import java.io.IOException; import java.util.Objects; +import java.util.Optional; +import java.util.regex.Matcher; import java.util.regex.Pattern; import static java.util.Objects.requireNonNull; @@ -29,7 +31,15 @@ public class GetReindexResponse extends ActionResponse implements ToXContentObje private final TaskResult task; - private static final Pattern DESCRIPTION_FILTER_PATTERN = Pattern.compile("(?s) query=.*?(?=\\]\\[[^\\]]*\\] to \\[)"); + /** + * Matches a reindex description and captures only the safe fields we want to expose: + * group(1) = optional safe remote info (scheme, host, port, pathPrefix), null for local reindex + * group(2) = source indices + * group(3) = destination index + */ + private static final Pattern DESCRIPTION_PATTERN = Pattern.compile( + "(?s)^reindex from (?:\\[((?:scheme=\\S+ )?host=\\S+ port=\\d+(?:\\s+pathPrefix=\\S+)?) .+\\])?\\[([^\\]]*)].*to \\[([^\\]]*)]$" + ); public GetReindexResponse(TaskResult task) { this.task = requireNonNull(task, "task is required"); @@ -70,8 +80,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws // reindex specific TaskInfo serialization static XContentBuilder taskInfoToXContent(XContentBuilder builder, Params params, TaskInfo taskInfo) throws IOException { builder.field("id", taskInfo.node() + ":" + taskInfo.id()); - if (taskInfo.description() != null) { - builder.field("description", sanitizeDescription(taskInfo.description())); + Optional description = sanitizeDescription(taskInfo.description()); + if (description.isPresent()) { + builder.field("description", description.get()); } builder.timestampFieldsFromUnixEpochMillis("start_time_in_millis", "start_time", taskInfo.startTime()); if (builder.humanReadable()) { @@ -86,8 +97,27 @@ static XContentBuilder taskInfoToXContent(XContentBuilder builder, Params params return builder; } - static String sanitizeDescription(String description) { - return DESCRIPTION_FILTER_PATTERN.matcher(description).replaceAll(""); + /** + * Selectively constructs a safe description by extracting only the fields we want to expose and discarding everything else. + * Returns empty if the description cannot be parsed, so we don't risk exposing sensitive data from an unrecognised format. + */ + static Optional sanitizeDescription(String description) { + if (description == null) { + return Optional.empty(); + } + Matcher matcher = DESCRIPTION_PATTERN.matcher(description); + if (matcher.matches()) { + String remoteInfo = matcher.group(1); + String sourceIndices = matcher.group(2); + String destIndex = matcher.group(3); + StringBuilder sb = new StringBuilder("reindex from "); + if (remoteInfo != null) { + sb.append('[').append(remoteInfo).append(']'); + } + sb.append('[').append(sourceIndices).append("] to [").append(destIndex).append(']'); + return Optional.of(sb.toString()); + } + return Optional.empty(); } @Override diff --git a/modules/reindex-management/src/test/java/org/elasticsearch/reindex/management/GetReindexResponseTests.java b/modules/reindex-management/src/test/java/org/elasticsearch/reindex/management/GetReindexResponseTests.java index e786e79f9c73b..12843e1b98814 100644 --- a/modules/reindex-management/src/test/java/org/elasticsearch/reindex/management/GetReindexResponseTests.java +++ b/modules/reindex-management/src/test/java/org/elasticsearch/reindex/management/GetReindexResponseTests.java @@ -11,17 +11,42 @@ import org.elasticsearch.test.ESTestCase; +import java.util.Optional; + import static org.elasticsearch.reindex.management.GetReindexResponse.sanitizeDescription; import static org.hamcrest.Matchers.equalTo; public class GetReindexResponseTests extends ESTestCase { + public void testSanitizeDescriptionNull() { + assertThat(sanitizeDescription(null), equalTo(Optional.empty())); + } + public void testSanitizeDescriptionLocalReindex() { - assertThat(sanitizeDescription("reindex from [source] to [dest]"), equalTo("reindex from [source] to [dest]")); + assertThat(sanitizeDescription("reindex from [source] to [dest]"), equalTo(Optional.of("reindex from [source] to [dest]"))); } public void testSanitizeDescriptionLocalReindexMultipleIndices() { - assertThat(sanitizeDescription("reindex from [source1, source2] to [dest]"), equalTo("reindex from [source1, source2] to [dest]")); + assertThat( + sanitizeDescription("reindex from [source1, source2] to [dest]"), + equalTo(Optional.of("reindex from [source1, source2] to [dest]")) + ); + } + + public void testSanitizeDescriptionLocalReindexWithScript() { + assertThat( + sanitizeDescription( + "reindex from [source] updated with Script{type=inline, lang='painless'," + + " idOrCode='ctx._source.tag = 'host=localhost port=9200 username=admin password=secret''," + + " options={}, params={}}" + + " to [dest]" + ), + equalTo(Optional.of("reindex from [source] to [dest]")) + ); + } + + public void testSanitizeDescriptionNonReindexDescription() { + assertThat(sanitizeDescription("some other task description"), equalTo(Optional.empty())); } public void testSanitizeDescriptionRemoteWithAllFields() { @@ -29,21 +54,21 @@ public void testSanitizeDescriptionRemoteWithAllFields() { sanitizeDescription( "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=real_user password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } public void testSanitizeDescriptionRemoteQueryOnly() { assertThat( sanitizeDescription("reindex from [host=example.com port=9200 query={\"match_all\":{}}][source] to [dest]"), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } public void testSanitizeDescriptionRemoteUsernameOnly() { assertThat( sanitizeDescription("reindex from [host=example.com port=9200 query={\"match_all\":{}} username=real_user][source] to [dest]"), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -53,7 +78,7 @@ public void testSanitizeDescriptionRemoteWithSchemeAndPathPrefix() { "reindex from [scheme=https host=example.com port=9200 pathPrefix=/es query={\"match_all\":{}}" + " username=real_user password=<<>>][source] to [dest]" ), - equalTo("reindex from [scheme=https host=example.com port=9200 pathPrefix=/es][source] to [dest]") + equalTo(Optional.of("reindex from [scheme=https host=example.com port=9200 pathPrefix=/es][source] to [dest]")) ); } @@ -63,7 +88,7 @@ public void testSanitizeDescriptionQueryWithPrettyPrintedJson() { "reindex from [host=example.com port=9200 query={\n \"match_all\" : {\n \"boost\" : 1.0\n }\n}" + " username=real_user password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -73,7 +98,7 @@ public void testSanitizeDescriptionQueryWithArrayBrackets() { "reindex from [host=example.com port=9200 query={\"terms\":{\"status\":[\"active\",\"pending\"]}}" + " username=real_user password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -83,7 +108,7 @@ public void testSanitizeDescriptionQueryWithNestedArrayBrackets() { "reindex from [host=example.com port=9200 query={\"bool\":{\"should\":[{\"terms\":{\"x\":[\"a\",\"b\"]}}," + "{\"terms\":{\"y\":[\"c\"]}}]}} username=real_user password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -92,7 +117,7 @@ public void testSanitizeDescriptionQueryWithLuceneRangeSyntax() { sanitizeDescription( "reindex from [host=example.com port=9200 query={\"query_string\":{\"query\":\"field:[1 TO 10]\"}}][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -102,7 +127,7 @@ public void testSanitizeDescriptionQueryContainingUsernameEquals() { "reindex from [host=example.com port=9200 query={\"query_string\":{\"query\":\" username=admin\"}}" + " username=real_user password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -112,7 +137,7 @@ public void testSanitizeDescriptionQueryContainingPasswordEquals() { "reindex from [host=example.com port=9200 query={\"query_string\":{\"query\":\" password=secret\"}}" + " username=real_user password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -122,7 +147,7 @@ public void testSanitizeDescriptionQueryContainingUsernameFieldName() { "reindex from [host=example.com port=9200 query={\"term\":{\"username\":\"john\"}}" + " username=real_user password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -132,7 +157,7 @@ public void testSanitizeDescriptionQueryContainingBracketPair() { "reindex from [host=example.com port=9200 query={\"query_string\":{\"query\":\"a][b\"}}" + " username=real_user][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -141,7 +166,7 @@ public void testSanitizeDescriptionUsernameWithBrackets() { sanitizeDescription( "reindex from [host=example.com port=9200 query={\"match_all\":{}}" + " username=user]name password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -150,7 +175,7 @@ public void testSanitizeDescriptionUsernameWithBracketPair() { sanitizeDescription( "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=user][name password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -159,7 +184,7 @@ public void testSanitizeDescriptionUsernameWithSpecialChars() { sanitizeDescription( "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=user@domain[0] password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } @@ -168,7 +193,20 @@ public void testSanitizeDescriptionUsernameWithWhitespace() { sanitizeDescription( "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=user name password=<<>>][source] to [dest]" ), - equalTo("reindex from [host=example.com port=9200][source] to [dest]") + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) + ); + } + + public void testSanitizeDescriptionRemoteWithScript() { + assertThat( + sanitizeDescription( + "reindex from [host=example.com port=9200 query={\"match_all\":{}} username=real_user password=<<>>][source]" + + " updated with Script{type=inline, lang='painless'," + + " idOrCode='ctx._source.tag = 'host=localhost port=9200 username=admin password=secret''," + + " options={}, params={}}" + + " to [dest]" + ), + equalTo(Optional.of("reindex from [host=example.com port=9200][source] to [dest]")) ); } }