diff --git a/x-pack/plugin/inference/qa/inference-with-security/build.gradle b/x-pack/plugin/inference/qa/inference-with-security/build.gradle new file mode 100644 index 0000000000000..e1a888bff90af --- /dev/null +++ b/x-pack/plugin/inference/qa/inference-with-security/build.gradle @@ -0,0 +1,15 @@ +apply plugin: 'elasticsearch.internal-yaml-rest-test' + +dependencies { + testImplementation(testArtifact(project(xpackModule('core')))) + testImplementation(testArtifact(project(':server'))) + testImplementation(project(':x-pack:plugin:inference:qa:test-service-plugin')) + testImplementation project(':modules:reindex') + testImplementation project(':modules:mapper-extras') + clusterPlugins project(':x-pack:plugin:inference:qa:test-service-plugin') +} + +tasks.named('yamlRestTest') { + usesDefaultDistribution("to be triaged") +} + diff --git a/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/java/org/elasticsearch/xpack/inference/InferenceWithSecurityRestIT.java b/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/java/org/elasticsearch/xpack/inference/InferenceWithSecurityRestIT.java new file mode 100644 index 0000000000000..ab4288b5904c4 --- /dev/null +++ b/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/java/org/elasticsearch/xpack/inference/InferenceWithSecurityRestIT.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +package org.elasticsearch.xpack.inference; + +import com.carrotsearch.randomizedtesting.annotations.ParametersFactory; + +import org.elasticsearch.client.Request; +import org.elasticsearch.common.Strings; +import org.elasticsearch.common.settings.SecureString; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.common.util.concurrent.ThreadContext; +import org.elasticsearch.test.cluster.ElasticsearchCluster; +import org.elasticsearch.test.cluster.local.distribution.DistributionType; +import org.elasticsearch.test.cluster.util.resource.Resource; +import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate; +import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase; +import org.junit.After; +import org.junit.ClassRule; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +public class InferenceWithSecurityRestIT extends ESClientYamlSuiteTestCase { + + private static final String TEST_ADMIN_USERNAME = "x_pack_rest_user"; + private static final String TEST_ADMIN_PASSWORD = "x-pack-test-password"; + + private static final String INFERENCE_USERNAME = "inference_user"; + private static final String INFERENCE_PASSWORD = "inference_user_password"; + + @ClassRule + public static ElasticsearchCluster cluster = ElasticsearchCluster.local() + .systemProperty("tests.seed", System.getProperty("tests.seed")) + .setting("xpack.security.enabled", "true") + .setting("xpack.license.self_generated.type", "trial") + .rolesFile(Resource.fromClasspath("roles.yml")) + .user(TEST_ADMIN_USERNAME, TEST_ADMIN_PASSWORD) // admin user for setup and teardown + .user(INFERENCE_USERNAME, INFERENCE_PASSWORD, "monitor_only_user", false) + .plugin("inference-service-test") + .distribution(DistributionType.DEFAULT) + .build(); + + public InferenceWithSecurityRestIT(final ClientYamlTestCandidate testCandidate) { + super(testCandidate); + } + + @Override + protected Settings restClientSettings() { + String token = basicAuthHeaderValue(INFERENCE_USERNAME, new SecureString(INFERENCE_PASSWORD.toCharArray())); + return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build(); + } + + @Override + protected Settings restAdminSettings() { + String token = basicAuthHeaderValue(TEST_ADMIN_USERNAME, new SecureString(TEST_ADMIN_PASSWORD.toCharArray())); + return Settings.builder().put(ThreadContext.PREFIX + ".Authorization", token).build(); + } + + @Override + protected String getTestRestCluster() { + return cluster.getHttpAddresses(); + } + + @ParametersFactory + public static Iterable parameters() throws Exception { + return ESClientYamlSuiteTestCase.createParameters(); + } + + @After + public void cleanup() throws Exception { + for (var model : getAllModels()) { + var inferenceId = model.get("inference_id"); + try { + var endpoint = Strings.format("_inference/%s?force", inferenceId); + adminClient().performRequest(new Request("DELETE", endpoint)); + } catch (Exception ex) { + logger.warn(() -> "failed to delete inference endpoint " + inferenceId, ex); + } + } + } + + @SuppressWarnings("unchecked") + static List> getAllModels() throws IOException { + var request = new Request("GET", "_inference/_all"); + var response = client().performRequest(request); + return (List>) entityAsMap(response).get("endpoints"); + } +} diff --git a/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/resources/rest-api-spec/test/inference/70_text_similarity_rank_retriever.yml b/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/resources/rest-api-spec/test/inference/70_text_similarity_rank_retriever.yml new file mode 100644 index 0000000000000..80f6fa77ea9c0 --- /dev/null +++ b/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/resources/rest-api-spec/test/inference/70_text_similarity_rank_retriever.yml @@ -0,0 +1,123 @@ +setup: + - skip: + features: + - close_to + - requires: + test_runner_features: "close_to" + + - do: + inference.put: + task_type: rerank + inference_id: my-rerank-model + body: > + { + "service": "test_reranking_service", + "service_settings": { + "model_id": "my_model", + "api_key": "abc64" + }, + "task_settings": { + } + } + + - do: + indices.create: + index: test-index + body: + mappings: + properties: + text: + type: text + topic: + type: keyword + subtopic: + type: keyword + inference_text_field: + type: text + + - do: + index: + index: test-index + id: doc_2 + body: + text: "The phases of the Moon come from the position of the Moon relative to the Earth and Sun." + topic: [ "science" ] + subtopic: [ "astronomy" ] + inference_text_field: "0" + refresh: true + + - do: + index: + index: test-index + id: doc_3 + body: + text: "Sun Moon Lake is a lake in Nantou County, Taiwan. It is the largest lake in Taiwan." + topic: [ "geography" ] + inference_text_field: "1" + refresh: true + + - do: + index: + index: test-index + id: doc_1 + body: + text: "As seen from Earth, a solar eclipse happens when the Moon is directly between the Earth and the Sun." + topic: [ "science" ] + subtopic: [ "technology" ] + inference_text_field: "-1" + refresh: true + +--- +"Simple text similarity rank retriever": + + - requires: + cluster_features: "test_reranking_service.parse_text_as_score" + reason: test_reranking_service can now parse provided input as score to provide deterministic ranks + + - do: + search: + index: test-index + body: + track_total_hits: true + fields: [ "text", "topic" ] + retriever: + text_similarity_reranker: + retriever: + # this one returns docs 1 and 2 + standard: + query: + bool: { + should: [ + { + constant_score: { + filter: { + term: { + subtopic: "technology" + } + }, + boost: 10 + } + }, + { + constant_score: { + filter: { + term: { + subtopic: "astronomy" + } + }, + boost: 1 + } + } + ] + } + rank_window_size: 10 + inference_id: my-rerank-model + inference_text: "How often does the moon hide the sun?" + field: inference_text_field + size: 10 + + - match: { hits.total.value: 2 } + - length: { hits.hits: 2 } + + - match: { hits.hits.0._id: "doc_2" } + - match: { hits.hits.1._id: "doc_1" } diff --git a/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/resources/roles.yml b/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/resources/roles.yml new file mode 100644 index 0000000000000..815292d75e9b2 --- /dev/null +++ b/x-pack/plugin/inference/qa/inference-with-security/src/yamlRestTest/resources/roles.yml @@ -0,0 +1,8 @@ +monitor_only_user: + cluster: + - monitor + - manage_inference + indices: + - names: [ 'test-index*' ] + privileges: + - all