From 8ccca03f258d8dba7dac127f5558156638d5a055 Mon Sep 17 00:00:00 2001 From: Sid Date: Fri, 2 Aug 2024 12:36:17 +0200 Subject: [PATCH 1/7] Add debug logging to flaky Session cleanup test (#189777) ## Summary Add settings to the ES Test cluster to enable debug logs so that if this test fails in the future, we will have more logs to investigate the issue. --- .../tests/session_lifespan/cleanup.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/x-pack/test/security_api_integration/tests/session_lifespan/cleanup.ts b/x-pack/test/security_api_integration/tests/session_lifespan/cleanup.ts index 8186cdbded722..5f7efaefd6242 100644 --- a/x-pack/test/security_api_integration/tests/session_lifespan/cleanup.ts +++ b/x-pack/test/security_api_integration/tests/session_lifespan/cleanup.ts @@ -19,6 +19,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertestWithoutAuth'); const es = getService('es'); + const esSupertest = getService('esSupertest'); const esDeleteAllIndices = getService('esDeleteAllIndices'); const config = getService('config'); const randomness = getService('randomness'); @@ -72,9 +73,19 @@ export default function ({ getService }: FtrProviderContext) { return cookie; } + async function addESDebugLoggingSettings() { + const addLogging = { + persistent: { + 'logger.org.elasticsearch.xpack.security.authc': 'debug', + }, + }; + await esSupertest.put('/_cluster/settings').send(addLogging).expect(200); + } + describe('Session Lifespan cleanup', () => { beforeEach(async () => { await es.cluster.health({ index: '.kibana_security_session*', wait_for_status: 'green' }); + await addESDebugLoggingSettings(); await esDeleteAllIndices('.kibana_security_session*'); }); From 4546c8ed887c0bc0ec349ed606cd2a6736416693 Mon Sep 17 00:00:00 2001 From: Joe McElroy Date: Fri, 2 Aug 2024 11:39:07 +0100 Subject: [PATCH 2/7] [Search] [Playground] Omit question from session state (#189716) ## Summary Bug within session persistence where it may persist the question into form state which in turn gets persisted into localstorage. This change omits the question from the session state. ### Checklist Delete any items that are not applicable to this PR. - [ ] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/packages/kbn-i18n/README.md) - [ ] [Documentation](https://www.elastic.co/guide/en/kibana/master/development-documentation.html) was added for features that require explanation or tutorials - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios - [ ] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed - [ ] Any UI touched in this PR is usable by keyboard only (learn more about [keyboard accessibility](https://webaim.org/techniques/keyboard/)) - [ ] Any UI touched in this PR does not create any new axe failures (run axe in browser: [FF](https://addons.mozilla.org/en-US/firefox/addon/axe-devtools/), [Chrome](https://chrome.google.com/webstore/detail/axe-web-accessibility-tes/lhdoppojpmngadmnindnejefpokejbdd?hl=en-US)) - [ ] If a plugin configuration key changed, check if it needs to be allowlisted in the cloud and added to the [docker list](https://github.com/elastic/kibana/blob/main/src/dev/build/tasks/os_packages/docker_generator/resources/base/bin/kibana-docker) - [ ] This renders correctly on smaller devices using a responsive layout. (You can test this [in your browser](https://www.browserstack.com/guide/responsive-testing-on-local-server)) - [ ] This was checked for [cross-browser compatibility](https://www.elastic.co/support/matrix#matrix_browsers) --- .../public/providers/form_provider.test.tsx | 2 ++ .../public/providers/form_provider.tsx | 5 ++++- .../page_objects/search_playground_page.ts | 20 +++++++++++++++++++ .../search_playground/playground_overview.ts | 10 ++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/search_playground/public/providers/form_provider.test.tsx b/x-pack/plugins/search_playground/public/providers/form_provider.test.tsx index 73def5031615e..f5b8f50a43b6a 100644 --- a/x-pack/plugins/search_playground/public/providers/form_provider.test.tsx +++ b/x-pack/plugins/search_playground/public/providers/form_provider.test.tsx @@ -130,6 +130,8 @@ describe('FormProvider', () => { act(() => { setValue(ChatFormFields.prompt, 'New prompt'); + // omit question from the session state + setValue(ChatFormFields.question, 'dont save me'); }); await waitFor(() => { diff --git a/x-pack/plugins/search_playground/public/providers/form_provider.tsx b/x-pack/plugins/search_playground/public/providers/form_provider.tsx index 03c0ce5652e19..fc7c1e8a4c12f 100644 --- a/x-pack/plugins/search_playground/public/providers/form_provider.tsx +++ b/x-pack/plugins/search_playground/public/providers/form_provider.tsx @@ -36,7 +36,10 @@ const getLocalSession = (storage: Storage): PartialChatForm => { } }; -const setLocalSession = (state: PartialChatForm, storage: Storage) => { +const setLocalSession = (formState: PartialChatForm, storage: Storage) => { + // omit question from the session state + const { question, ...state } = formState; + storage.setItem(LOCAL_STORAGE_KEY, JSON.stringify(state)); }; diff --git a/x-pack/test/functional/page_objects/search_playground_page.ts b/x-pack/test/functional/page_objects/search_playground_page.ts index 8e59c7cc3e37a..d03457298a7c7 100644 --- a/x-pack/test/functional/page_objects/search_playground_page.ts +++ b/x-pack/test/functional/page_objects/search_playground_page.ts @@ -47,6 +47,12 @@ export function SearchPlaygroundPageProvider({ getService }: FtrProviderContext) }, }); }, + + async expectInSession(key: string, value: string | undefined): Promise { + const session = (await browser.getLocalStorageItem(SESSION_KEY)) || '{}'; + const state = JSON.parse(session); + expect(state[key]).to.be(value); + }, }, PlaygroundStartChatPage: { async expectPlaygroundStartChatPageComponentsToExist() { @@ -151,6 +157,20 @@ export function SearchPlaygroundPageProvider({ getService }: FtrProviderContext) await testSubjects.existOrFail('summarizationPanel'); }, + async updatePrompt(prompt: string) { + await testSubjects.setValue('instructionsPrompt', prompt); + }, + + async updateQuestion(question: string) { + await testSubjects.setValue('questionInput', question); + }, + + async expectQuestionInputToBeEmpty() { + const questionInput = await testSubjects.find('questionInput'); + const question = await questionInput.getAttribute('value'); + expect(question).to.be.empty(); + }, + async sendQuestion() { await testSubjects.setValue('questionInput', 'test question'); await testSubjects.click('sendQuestionButton'); diff --git a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts index e5ef4f8d04af6..476b47b060b2c 100644 --- a/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts +++ b/x-pack/test_serverless/functional/test_suites/search/search_playground/playground_overview.ts @@ -192,6 +192,16 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { 'You are a fireman in london that helps answering question-answering tasks.' ); }); + + it("saves a session to localstorage when it's updated", async () => { + await pageObjects.searchPlayground.session.setSession(); + await browser.refresh(); + await pageObjects.searchPlayground.PlaygroundChatPage.navigateToChatPage(); + await pageObjects.searchPlayground.PlaygroundChatPage.updatePrompt("You're a doctor"); + await pageObjects.searchPlayground.PlaygroundChatPage.updateQuestion('i have back pain'); + await pageObjects.searchPlayground.session.expectInSession('prompt', "You're a doctor"); + await pageObjects.searchPlayground.session.expectInSession('question', undefined); + }); }); after(async () => { From e47c345f7cb13be25c7d23359dca989ac1850d09 Mon Sep 17 00:00:00 2001 From: Maxim Palenov Date: Fri, 2 Aug 2024 12:42:05 +0200 Subject: [PATCH 3/7] [Security Solution] Auto bundle endpoint exceptions api openapi specs (#189665) **Addresses**: https://github.com/elastic/kibana/issues/184428 ## Summary This PR adds scripts for automatic bundling of Endpoint Exceptions API OpenAPI specs as a part of PR pipeline. Corresponding result bundles are automatically committed to the Endpoint Exceptions common package `kbn-securitysolution-endpoint-exceptions-common` in the `docs/openapi/ess/` and `docs/openapi/serverless` folders (similar to https://github.com/elastic/kibana/pull/186384). --- .../security_solution_codegen.sh | 3 + .../security_solution_openapi_bundling.sh | 3 + ...eptions_api_2023_10_31.bundled.schema.yaml | 865 ++++++++++++++++++ ...eptions_api_2023_10_31.bundled.schema.yaml | 865 ++++++++++++++++++ .../package.json | 3 +- .../scripts/openapi_bundle.js | 49 + ...imeline_api_2023_10_31.bundled.schema.yaml | 5 +- ...imeline_api_2023_10_31.bundled.schema.yaml | 5 +- .../scripts/openapi/bundle_timeline.js | 20 +- 9 files changed, 1807 insertions(+), 11 deletions(-) create mode 100644 packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml create mode 100644 packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml create mode 100644 packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js diff --git a/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh b/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh index ef4d69b2a295e..59651402c9d83 100755 --- a/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh +++ b/.buildkite/scripts/steps/code_generation/security_solution_codegen.sh @@ -15,6 +15,9 @@ echo -e "\n[Security Solution OpenAPI Code Generation] Lists Common Package\n" echo -e "\n[Security Solution OpenAPI Code Generation] Exceptions Common Package\n" (cd packages/kbn-securitysolution-exceptions-common && yarn openapi:generate) +echo -e "\n[Security Solution OpenAPI Code Generation] Endpoint Exceptions Common Package\n" +(cd packages/kbn-securitysolution-endpoint-exceptions-common && yarn openapi:generate) + echo -e "\n[Security Solution OpenAPI Code Generation] Security Solution Plugin\n" (cd x-pack/plugins/security_solution && yarn openapi:generate) diff --git a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh index 798c3cdbb9b76..2c23d9850afa4 100755 --- a/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh +++ b/.buildkite/scripts/steps/openapi_bundling/security_solution_openapi_bundling.sh @@ -21,6 +21,9 @@ echo -e "\n[Security Solution OpenAPI Bundling] Lists API\n" echo -e "\n[Security Solution OpenAPI Bundling] Exceptions API\n" (cd packages/kbn-securitysolution-exceptions-common && yarn openapi:bundle) +echo -e "\n[Security Solution OpenAPI Bundling] Endpoint Exceptions API\n" +(cd packages/kbn-securitysolution-endpoint-exceptions-common && yarn openapi:bundle) + echo -e "\n[Security Solution OpenAPI Bundling] Endpoint Management API\n" (cd x-pack/plugins/security_solution && yarn openapi:bundle:endpoint-management) diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml new file mode 100644 index 0000000000000..166d29063f351 --- /dev/null +++ b/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/ess/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml @@ -0,0 +1,865 @@ +openapi: 3.0.3 +info: + description: Endpoint Exceptions API allow you to manage Endpoint lists. + title: Security Solution Endpoint Exceptions API (Elastic Cloud and self-hosted) + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + /api/endpoint_list: + post: + description: Creates an endpoint list or does nothing if the list already exists + operationId: CreateEndpointList + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Creates an endpoint list + tags: + - Endpoint exceptions API + /api/endpoint_list/items: + delete: + operationId: DeleteEndpointListItem + parameters: + - description: Either `id` or `item_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemId' + - description: Either `id` or `item_id` must be specified + in: query + name: item_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemHumanId' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list item not found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Deletes an endpoint list item + tags: + - Endpoint exceptions API + get: + operationId: ReadEndpointListItem + parameters: + - description: Either `id` or `item_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemId' + - description: Either `id` or `item_id` must be specified + in: query + name: item_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemHumanId' + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/EndpointListItem' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list item not found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Reads an endpoint list item + tags: + - Endpoint exceptions API + post: + operationId: CreateEndpointListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + comments: + $ref: '#/components/schemas/ExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + default: [] + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - type + - name + - description + - entries + description: Exception list item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list item already exists + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Creates an endpoint list item + tags: + - Endpoint exceptions API + put: + operationId: UpdateEndpointListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + comments: + $ref: '#/components/schemas/ExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + id: + $ref: '#/components/schemas/ExceptionListItemId' + description: Either `id` or `item_id` must be specified + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + description: Either `id` or `item_id` must be specified + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - type + - name + - description + - entries + description: Exception list item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list item not found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Updates an endpoint list item + tags: + - Endpoint exceptions API + /api/endpoint_list/items/_find: + get: + operationId: FindEndpointListItems + parameters: + - description: > + Filters the returned results according to the value of the specified + field, + + using the `:` syntax. + in: query + name: filter + required: false + schema: + $ref: '#/components/schemas/FindEndpointListItemsFilter' + - description: The page number to return + in: query + name: page + required: false + schema: + minimum: 0 + type: integer + - description: The number of exception list items to return per page + in: query + name: per_page + required: false + schema: + minimum: 0 + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/NonEmptyString' + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + items: + $ref: '#/components/schemas/EndpointListItem' + type: array + page: + minimum: 0 + type: integer + per_page: + minimum: 0 + type: integer + pit: + type: string + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list not found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Finds endpoint list items + tags: + - Endpoint exceptions API +components: + schemas: + EndpointList: + oneOf: + - $ref: '#/components/schemas/ExceptionList' + - additionalProperties: false + type: object + EndpointListItem: + $ref: '#/components/schemas/ExceptionListItem' + ExceptionList: + type: object + properties: + _version: + type: string + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ExceptionListDescription' + id: + $ref: '#/components/schemas/ExceptionListId' + immutable: + type: boolean + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListMeta' + name: + $ref: '#/components/schemas/ExceptionListName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + os_types: + $ref: '#/components/schemas/ExceptionListOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListTags' + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ExceptionListType' + updated_at: + format: date-time + type: string + updated_by: + type: string + version: + $ref: '#/components/schemas/ExceptionListVersion' + required: + - id + - list_id + - type + - name + - description + - immutable + - namespace_type + - version + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ExceptionListDescription: + type: string + ExceptionListHumanId: + $ref: '#/components/schemas/NonEmptyString' + description: 'Human readable string identifier, e.g. `trusted-linux-processes`' + ExceptionListId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItem: + type: object + properties: + _version: + type: string + comments: + $ref: '#/components/schemas/ExceptionListItemCommentArray' + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + id: + $ref: '#/components/schemas/ExceptionListItemId' + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ExceptionListItemType' + updated_at: + format: date-time + type: string + updated_by: + type: string + required: + - id + - item_id + - list_id + - type + - name + - description + - entries + - namespace_type + - comments + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + created_at: + format: date-time + type: string + created_by: + $ref: '#/components/schemas/NonEmptyString' + id: + $ref: '#/components/schemas/NonEmptyString' + updated_at: + format: date-time + type: string + updated_by: + $ref: '#/components/schemas/NonEmptyString' + required: + - id + - comment + - created_at + - created_by + ExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/ExceptionListItemComment' + type: array + ExceptionListItemDescription: + type: string + ExceptionListItemEntry: + anyOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryList' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + - $ref: '#/components/schemas/ExceptionListItemEntryNested' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchWildcard' + discriminator: + propertyName: type + ExceptionListItemEntryArray: + items: + $ref: '#/components/schemas/ExceptionListItemEntry' + type: array + ExceptionListItemEntryExists: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - exists + type: string + required: + - type + - field + - operator + ExceptionListItemEntryList: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + list: + type: object + properties: + id: + $ref: '#/components/schemas/ListId' + type: + $ref: '#/components/schemas/ListType' + required: + - id + - type + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - list + type: string + required: + - type + - field + - list + - operator + ExceptionListItemEntryMatch: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - match + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - type + - field + - value + - operator + ExceptionListItemEntryMatchAny: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - match_any + type: string + value: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + required: + - type + - field + - value + - operator + ExceptionListItemEntryMatchWildcard: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - wildcard + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - type + - field + - value + - operator + ExceptionListItemEntryNested: + type: object + properties: + entries: + items: + $ref: '#/components/schemas/ExceptionListItemEntryNestedEntryItem' + minItems: 1 + type: array + field: + $ref: '#/components/schemas/NonEmptyString' + type: + enum: + - nested + type: string + required: + - type + - field + - entries + ExceptionListItemEntryNestedEntryItem: + oneOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + ExceptionListItemEntryOperator: + enum: + - excluded + - included + type: string + ExceptionListItemHumanId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemMeta: + additionalProperties: true + type: object + ExceptionListItemName: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemOsTypeArray: + items: + $ref: '#/components/schemas/ExceptionListOsType' + type: array + ExceptionListItemTags: + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + ExceptionListItemType: + enum: + - simple + type: string + ExceptionListMeta: + additionalProperties: true + type: object + ExceptionListName: + type: string + ExceptionListOsType: + enum: + - linux + - macos + - windows + type: string + ExceptionListOsTypeArray: + items: + $ref: '#/components/schemas/ExceptionListOsType' + type: array + ExceptionListTags: + items: + type: string + type: array + ExceptionListType: + enum: + - detection + - rule_default + - endpoint + - endpoint_trusted_apps + - endpoint_events + - endpoint_host_isolation_exceptions + - endpoint_blocklists + type: string + ExceptionListVersion: + minimum: 1 + type: integer + ExceptionNamespaceType: + description: > + Determines whether the exception container is available in all Kibana + spaces or just the space + + in which it is created, where: + + + - `single`: Only available in the Kibana space in which it is created. + + - `agnostic`: Available in all Kibana spaces. + enum: + - agnostic + - single + type: string + FindEndpointListItemsFilter: + $ref: '#/components/schemas/NonEmptyString' + ListId: + $ref: '#/components/schemas/NonEmptyString' + ListType: + enum: + - binary + - boolean + - byte + - date + - date_nanos + - date_range + - double + - double_range + - float + - float_range + - geo_point + - geo_shape + - half_float + - integer + - integer_range + - ip + - ip_range + - keyword + - long + - long_range + - shape + - short + - text + type: string + NonEmptyString: + description: A string that is not empty and does not contain only whitespace + minLength: 1 + pattern: ^(?! *$).+$ + type: string + PlatformErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: integer + required: + - statusCode + - error + - message + SiemErrorResponse: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + securitySchemes: + BasicAuth: + scheme: basic + type: http +security: + - BasicAuth: [] diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml b/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml new file mode 100644 index 0000000000000..fe40b86970bfb --- /dev/null +++ b/packages/kbn-securitysolution-endpoint-exceptions-common/docs/openapi/serverless/security_solution_endpoint_exceptions_api_2023_10_31.bundled.schema.yaml @@ -0,0 +1,865 @@ +openapi: 3.0.3 +info: + description: Endpoint Exceptions API allow you to manage Endpoint lists. + title: Security Solution Endpoint Exceptions API (Elastic Cloud Serverless) + version: '2023-10-31' +servers: + - url: 'http://{kibana_host}:{port}' + variables: + kibana_host: + default: localhost + port: + default: '5601' +paths: + /api/endpoint_list: + post: + description: Creates an endpoint list or does nothing if the list already exists + operationId: CreateEndpointList + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointList' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Creates an endpoint list + tags: + - Endpoint exceptions API + /api/endpoint_list/items: + delete: + operationId: DeleteEndpointListItem + parameters: + - description: Either `id` or `item_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemId' + - description: Either `id` or `item_id` must be specified + in: query + name: item_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemHumanId' + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list item not found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Deletes an endpoint list item + tags: + - Endpoint exceptions API + get: + operationId: ReadEndpointListItem + parameters: + - description: Either `id` or `item_id` must be specified + in: query + name: id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemId' + - description: Either `id` or `item_id` must be specified + in: query + name: item_id + required: false + schema: + $ref: '#/components/schemas/ExceptionListItemHumanId' + responses: + '200': + content: + application/json: + schema: + items: + $ref: '#/components/schemas/EndpointListItem' + type: array + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list item not found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Reads an endpoint list item + tags: + - Endpoint exceptions API + post: + operationId: CreateEndpointListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + comments: + $ref: '#/components/schemas/ExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + default: [] + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - type + - name + - description + - entries + description: Exception list item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '409': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list item already exists + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Creates an endpoint list item + tags: + - Endpoint exceptions API + put: + operationId: UpdateEndpointListItem + requestBody: + content: + application/json: + schema: + type: object + properties: + _version: + type: string + comments: + $ref: '#/components/schemas/ExceptionListItemCommentArray' + default: [] + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + id: + $ref: '#/components/schemas/ExceptionListItemId' + description: Either `id` or `item_id` must be specified + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + description: Either `id` or `item_id` must be specified + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + default: [] + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + type: + $ref: '#/components/schemas/ExceptionListItemType' + required: + - type + - name + - description + - entries + description: Exception list item's properties + required: true + responses: + '200': + content: + application/json: + schema: + $ref: '#/components/schemas/EndpointListItem' + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list item not found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Updates an endpoint list item + tags: + - Endpoint exceptions API + /api/endpoint_list/items/_find: + get: + operationId: FindEndpointListItems + parameters: + - description: > + Filters the returned results according to the value of the specified + field, + + using the `:` syntax. + in: query + name: filter + required: false + schema: + $ref: '#/components/schemas/FindEndpointListItemsFilter' + - description: The page number to return + in: query + name: page + required: false + schema: + minimum: 0 + type: integer + - description: The number of exception list items to return per page + in: query + name: per_page + required: false + schema: + minimum: 0 + type: integer + - description: Determines which field is used to sort the results + in: query + name: sort_field + required: false + schema: + $ref: '#/components/schemas/NonEmptyString' + - description: 'Determines the sort order, which can be `desc` or `asc`' + in: query + name: sort_order + required: false + schema: + enum: + - desc + - asc + type: string + responses: + '200': + content: + application/json: + schema: + type: object + properties: + data: + items: + $ref: '#/components/schemas/EndpointListItem' + type: array + page: + minimum: 0 + type: integer + per_page: + minimum: 0 + type: integer + pit: + type: string + total: + minimum: 0 + type: integer + required: + - data + - page + - per_page + - total + description: Successful response + '400': + content: + application/json: + schema: + oneOf: + - $ref: '#/components/schemas/PlatformErrorResponse' + - $ref: '#/components/schemas/SiemErrorResponse' + description: Invalid input data + '401': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Unsuccessful authentication + '403': + content: + application/json: + schema: + $ref: '#/components/schemas/PlatformErrorResponse' + description: Insufficient privileges + '404': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Endpoint list not found + '500': + content: + application/json: + schema: + $ref: '#/components/schemas/SiemErrorResponse' + description: Internal server error + summary: Finds endpoint list items + tags: + - Endpoint exceptions API +components: + schemas: + EndpointList: + oneOf: + - $ref: '#/components/schemas/ExceptionList' + - additionalProperties: false + type: object + EndpointListItem: + $ref: '#/components/schemas/ExceptionListItem' + ExceptionList: + type: object + properties: + _version: + type: string + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ExceptionListDescription' + id: + $ref: '#/components/schemas/ExceptionListId' + immutable: + type: boolean + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListMeta' + name: + $ref: '#/components/schemas/ExceptionListName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + os_types: + $ref: '#/components/schemas/ExceptionListOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListTags' + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ExceptionListType' + updated_at: + format: date-time + type: string + updated_by: + type: string + version: + $ref: '#/components/schemas/ExceptionListVersion' + required: + - id + - list_id + - type + - name + - description + - immutable + - namespace_type + - version + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ExceptionListDescription: + type: string + ExceptionListHumanId: + $ref: '#/components/schemas/NonEmptyString' + description: 'Human readable string identifier, e.g. `trusted-linux-processes`' + ExceptionListId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItem: + type: object + properties: + _version: + type: string + comments: + $ref: '#/components/schemas/ExceptionListItemCommentArray' + created_at: + format: date-time + type: string + created_by: + type: string + description: + $ref: '#/components/schemas/ExceptionListItemDescription' + entries: + $ref: '#/components/schemas/ExceptionListItemEntryArray' + expire_time: + format: date-time + type: string + id: + $ref: '#/components/schemas/ExceptionListItemId' + item_id: + $ref: '#/components/schemas/ExceptionListItemHumanId' + list_id: + $ref: '#/components/schemas/ExceptionListHumanId' + meta: + $ref: '#/components/schemas/ExceptionListItemMeta' + name: + $ref: '#/components/schemas/ExceptionListItemName' + namespace_type: + $ref: '#/components/schemas/ExceptionNamespaceType' + os_types: + $ref: '#/components/schemas/ExceptionListItemOsTypeArray' + tags: + $ref: '#/components/schemas/ExceptionListItemTags' + tie_breaker_id: + type: string + type: + $ref: '#/components/schemas/ExceptionListItemType' + updated_at: + format: date-time + type: string + updated_by: + type: string + required: + - id + - item_id + - list_id + - type + - name + - description + - entries + - namespace_type + - comments + - tie_breaker_id + - created_at + - created_by + - updated_at + - updated_by + ExceptionListItemComment: + type: object + properties: + comment: + $ref: '#/components/schemas/NonEmptyString' + created_at: + format: date-time + type: string + created_by: + $ref: '#/components/schemas/NonEmptyString' + id: + $ref: '#/components/schemas/NonEmptyString' + updated_at: + format: date-time + type: string + updated_by: + $ref: '#/components/schemas/NonEmptyString' + required: + - id + - comment + - created_at + - created_by + ExceptionListItemCommentArray: + items: + $ref: '#/components/schemas/ExceptionListItemComment' + type: array + ExceptionListItemDescription: + type: string + ExceptionListItemEntry: + anyOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryList' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + - $ref: '#/components/schemas/ExceptionListItemEntryNested' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchWildcard' + discriminator: + propertyName: type + ExceptionListItemEntryArray: + items: + $ref: '#/components/schemas/ExceptionListItemEntry' + type: array + ExceptionListItemEntryExists: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - exists + type: string + required: + - type + - field + - operator + ExceptionListItemEntryList: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + list: + type: object + properties: + id: + $ref: '#/components/schemas/ListId' + type: + $ref: '#/components/schemas/ListType' + required: + - id + - type + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - list + type: string + required: + - type + - field + - list + - operator + ExceptionListItemEntryMatch: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - match + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - type + - field + - value + - operator + ExceptionListItemEntryMatchAny: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - match_any + type: string + value: + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + type: array + required: + - type + - field + - value + - operator + ExceptionListItemEntryMatchWildcard: + type: object + properties: + field: + $ref: '#/components/schemas/NonEmptyString' + operator: + $ref: '#/components/schemas/ExceptionListItemEntryOperator' + type: + enum: + - wildcard + type: string + value: + $ref: '#/components/schemas/NonEmptyString' + required: + - type + - field + - value + - operator + ExceptionListItemEntryNested: + type: object + properties: + entries: + items: + $ref: '#/components/schemas/ExceptionListItemEntryNestedEntryItem' + minItems: 1 + type: array + field: + $ref: '#/components/schemas/NonEmptyString' + type: + enum: + - nested + type: string + required: + - type + - field + - entries + ExceptionListItemEntryNestedEntryItem: + oneOf: + - $ref: '#/components/schemas/ExceptionListItemEntryMatch' + - $ref: '#/components/schemas/ExceptionListItemEntryMatchAny' + - $ref: '#/components/schemas/ExceptionListItemEntryExists' + ExceptionListItemEntryOperator: + enum: + - excluded + - included + type: string + ExceptionListItemHumanId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemId: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemMeta: + additionalProperties: true + type: object + ExceptionListItemName: + $ref: '#/components/schemas/NonEmptyString' + ExceptionListItemOsTypeArray: + items: + $ref: '#/components/schemas/ExceptionListOsType' + type: array + ExceptionListItemTags: + items: + $ref: '#/components/schemas/NonEmptyString' + type: array + ExceptionListItemType: + enum: + - simple + type: string + ExceptionListMeta: + additionalProperties: true + type: object + ExceptionListName: + type: string + ExceptionListOsType: + enum: + - linux + - macos + - windows + type: string + ExceptionListOsTypeArray: + items: + $ref: '#/components/schemas/ExceptionListOsType' + type: array + ExceptionListTags: + items: + type: string + type: array + ExceptionListType: + enum: + - detection + - rule_default + - endpoint + - endpoint_trusted_apps + - endpoint_events + - endpoint_host_isolation_exceptions + - endpoint_blocklists + type: string + ExceptionListVersion: + minimum: 1 + type: integer + ExceptionNamespaceType: + description: > + Determines whether the exception container is available in all Kibana + spaces or just the space + + in which it is created, where: + + + - `single`: Only available in the Kibana space in which it is created. + + - `agnostic`: Available in all Kibana spaces. + enum: + - agnostic + - single + type: string + FindEndpointListItemsFilter: + $ref: '#/components/schemas/NonEmptyString' + ListId: + $ref: '#/components/schemas/NonEmptyString' + ListType: + enum: + - binary + - boolean + - byte + - date + - date_nanos + - date_range + - double + - double_range + - float + - float_range + - geo_point + - geo_shape + - half_float + - integer + - integer_range + - ip + - ip_range + - keyword + - long + - long_range + - shape + - short + - text + type: string + NonEmptyString: + description: A string that is not empty and does not contain only whitespace + minLength: 1 + pattern: ^(?! *$).+$ + type: string + PlatformErrorResponse: + type: object + properties: + error: + type: string + message: + type: string + statusCode: + type: integer + required: + - statusCode + - error + - message + SiemErrorResponse: + type: object + properties: + message: + type: string + status_code: + type: integer + required: + - status_code + - message + securitySchemes: + BasicAuth: + scheme: basic + type: http +security: + - BasicAuth: [] diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/package.json b/packages/kbn-securitysolution-endpoint-exceptions-common/package.json index e07ac8c130c36..e3c9567435b0f 100644 --- a/packages/kbn-securitysolution-endpoint-exceptions-common/package.json +++ b/packages/kbn-securitysolution-endpoint-exceptions-common/package.json @@ -5,6 +5,7 @@ "private": true, "version": "1.0.0", "scripts": { - "openapi:generate": "node scripts/openapi_generate" + "openapi:generate": "node scripts/openapi_generate", + "openapi:bundle": "node scripts/openapi_bundle" } } diff --git a/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js b/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js new file mode 100644 index 0000000000000..2e35c5fc9cb90 --- /dev/null +++ b/packages/kbn-securitysolution-endpoint-exceptions-common/scripts/openapi_bundle.js @@ -0,0 +1,49 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +require('../../../src/setup_node_env'); +const { join, resolve } = require('path'); +const { bundle } = require('@kbn/openapi-bundler'); + +const ROOT = resolve(__dirname, '..'); + +(async () => { + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/serverless/security_solution_endpoint_exceptions_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['serverless'], + prototypeDocument: { + info: { + title: 'Security Solution Endpoint Exceptions API (Elastic Cloud Serverless)', + description: 'Endpoint Exceptions API allow you to manage Endpoint lists.', + }, + }, + }, + }); + + await bundle({ + sourceGlob: join(ROOT, 'api/**/*.schema.yaml'), + outputFilePath: join( + ROOT, + 'docs/openapi/ess/security_solution_endpoint_exceptions_api_{version}.bundled.schema.yaml' + ), + options: { + includeLabels: ['ess'], + prototypeDocument: { + info: { + title: 'Security Solution Endpoint Exceptions API (Elastic Cloud and self-hosted)', + description: 'Endpoint Exceptions API allow you to manage Endpoint lists.', + }, + }, + }, + }); +})(); diff --git a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 169029d2ff88b..05163df07c27a 100644 --- a/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/ess/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -1,6 +1,9 @@ openapi: 3.0.3 info: - title: Bundled OpenAPI specs + description: >- + You can create Timelines and Timeline templates via the API, as well as + import new Timelines from an ndjson file. + title: Security Solution Timeline API (Elastic Cloud and self-hosted) version: '2023-10-31' servers: - url: 'http://{kibana_host}:{port}' diff --git a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml index 169029d2ff88b..60825950b5187 100644 --- a/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml +++ b/x-pack/plugins/security_solution/docs/openapi/serverless/security_solution_timeline_api_2023_10_31.bundled.schema.yaml @@ -1,6 +1,9 @@ openapi: 3.0.3 info: - title: Bundled OpenAPI specs + description: >- + You can create Timelines and Timeline templates via the API, as well as + import new Timelines from an ndjson file. + title: Security Solution Timeline API (Elastic Cloud Serverless) version: '2023-10-31' servers: - url: 'http://{kibana_host}:{port}' diff --git a/x-pack/plugins/security_solution/scripts/openapi/bundle_timeline.js b/x-pack/plugins/security_solution/scripts/openapi/bundle_timeline.js index a828c3be1b5d3..ef3ab374be8bb 100644 --- a/x-pack/plugins/security_solution/scripts/openapi/bundle_timeline.js +++ b/x-pack/plugins/security_solution/scripts/openapi/bundle_timeline.js @@ -20,10 +20,12 @@ const ROOT = resolve(__dirname, '../..'); ), options: { includeLabels: ['serverless'], - specInfo: { - title: 'Security Solution Timeline API (Elastic Cloud Serverless)', - description: - 'You can create Timelines and Timeline templates via the API, as well as import new Timelines from an ndjson file.', + prototypeDocument: { + info: { + title: 'Security Solution Timeline API (Elastic Cloud Serverless)', + description: + 'You can create Timelines and Timeline templates via the API, as well as import new Timelines from an ndjson file.', + }, }, }, }); @@ -36,10 +38,12 @@ const ROOT = resolve(__dirname, '../..'); ), options: { includeLabels: ['ess'], - specInfo: { - title: 'Security Solution Timeline API (Elastic Cloud and self-hosted)', - description: - 'You can create Timelines and Timeline templates via the API, as well as import new Timelines from an ndjson file.', + prototypeDocument: { + info: { + title: 'Security Solution Timeline API (Elastic Cloud and self-hosted)', + description: + 'You can create Timelines and Timeline templates via the API, as well as import new Timelines from an ndjson file.', + }, }, }, }); From 183a2ea8cb8bed8ce7fbb1f615f808bce6576c05 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:45:23 +0200 Subject: [PATCH 4/7] Update dependency require-in-the-middle to ^7.4.0 (main) (#189749) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [![Mend Renovate](https://app.renovatebot.com/images/banner.svg)](https://renovatebot.com) This PR contains the following updates: | Package | Change | Age | Adoption | Passing | Confidence | |---|---|---|---|---|---| | [require-in-the-middle](https://togithub.com/elastic/require-in-the-middle) | [`^7.3.0` -> `^7.4.0`](https://renovatebot.com/diffs/npm/require-in-the-middle/7.3.0/7.4.0) | [![age](https://developer.mend.io/api/mc/badges/age/npm/require-in-the-middle/7.4.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![adoption](https://developer.mend.io/api/mc/badges/adoption/npm/require-in-the-middle/7.4.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![passing](https://developer.mend.io/api/mc/badges/compatibility/npm/require-in-the-middle/7.3.0/7.4.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/require-in-the-middle/7.3.0/7.4.0?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
elastic/require-in-the-middle (require-in-the-middle) ### [`v7.4.0`](https://togithub.com/elastic/require-in-the-middle/blob/HEAD/CHANGELOG.md#v740) [Compare Source](https://togithub.com/elastic/require-in-the-middle/compare/v7.3.0...v7.4.0) - Support hooking built-in Node.js loaded via [`process.getBuiltinModule`](https://nodejs.org/api/all.html#all_process_processgetbuiltinmoduleid), added in v22.3.[https://github.com/elastic/require-in-the-middle/pull/92](https://togithub.com/elastic/require-in-the-middle/pull/92)/pull/92)
--- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://www.mend.io/free-developer-tools/renovate/). View the [repository job log](https://developer.mend.io/github/elastic/kibana). --------- Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> Co-authored-by: Aleh Zasypkin --- package.json | 2 +- yarn.lock | 40 ++++++++++++++++++++-------------------- 2 files changed, 21 insertions(+), 21 deletions(-) diff --git a/package.json b/package.json index 8bc048ee0901d..4f28a04afdfe5 100644 --- a/package.json +++ b/package.json @@ -1184,7 +1184,7 @@ "remark-gfm": "1.0.0", "remark-parse-no-trim": "^8.0.4", "remark-stringify": "^8.0.3", - "require-in-the-middle": "^7.3.0", + "require-in-the-middle": "^7.4.0", "reselect": "^4.1.8", "resize-observer-polyfill": "1.5.1", "rison-node": "1.0.2", diff --git a/yarn.lock b/yarn.lock index 770ba1f29e2f5..00e59286e4db5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20252,12 +20252,12 @@ is-ci@^3.0.0: dependencies: ci-info "^3.2.0" -is-core-module@^2.11.0, is-core-module@^2.12.0, is-core-module@^2.12.1, is-core-module@^2.9.0: - version "2.12.1" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.12.1.tgz#0c0b6885b6f80011c71541ce15c8d66cf5a4f9fd" - integrity sha512-Q4ZuBAe2FUsKtyQJoQHlvP8OvBERxO3jEmy1I7hcRXcJBGGHFh/aJBswbXuS9sgrDH2QUO8ilkwNPHvHMd8clg== +is-core-module@^2.11.0, is-core-module@^2.12.1, is-core-module@^2.13.0: + version "2.13.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== dependencies: - has "^1.0.3" + hasown "^2.0.0" is-data-descriptor@^0.1.4: version "0.1.4" @@ -27635,14 +27635,14 @@ require-from-string@^2.0.2: resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== -require-in-the-middle@^7.0.1, require-in-the-middle@^7.1.1, require-in-the-middle@^7.3.0: - version "7.3.0" - resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-7.3.0.tgz#ce64a1083647dc07b3273b348357efac8a9945c9" - integrity sha512-nQFEv9gRw6SJAwWD2LrL0NmQvAcO7FBwJbwmr2ttPAacfy0xuiOjE5zt+zM4xDyuyvUaxBi/9gb2SoCyNEVJcw== +require-in-the-middle@^7.0.1, require-in-the-middle@^7.1.1, require-in-the-middle@^7.4.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/require-in-the-middle/-/require-in-the-middle-7.4.0.tgz#606977820d4b5f9be75e5a108ce34cfed25b3bb4" + integrity sha512-X34iHADNbNDfr6OTStIAHWSAvvKQRYgLO6duASaVf7J2VA3lvmNYboAHOuLC2huav1IwgZJtyEcJCKVzFxOSMQ== dependencies: - debug "^4.1.1" + debug "^4.3.5" module-details-from-path "^1.0.3" - resolve "^1.22.1" + resolve "^1.22.8" require-main-filename@^2.0.0: version "2.0.0" @@ -27743,21 +27743,21 @@ resolve@1.1.7: resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs= -resolve@^1.1.5, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1, resolve@^1.22.3, resolve@^1.3.2, resolve@^1.9.0: - version "1.22.3" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.3.tgz#4b4055349ffb962600972da1fdc33c46a4eb3283" - integrity sha512-P8ur/gp/AmbEzjr729bZnLjXK5Z+4P0zhIJgBgzqRih7hL7BOukHGtSTA3ACMY467GRFz3duQsi0bDZdR7DKdw== +resolve@^1.1.5, resolve@^1.1.6, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.10.1, resolve@^1.12.0, resolve@^1.14.2, resolve@^1.17.0, resolve@^1.18.1, resolve@^1.19.0, resolve@^1.20.0, resolve@^1.22.0, resolve@^1.22.1, resolve@^1.22.3, resolve@^1.22.8, resolve@^1.3.2, resolve@^1.9.0: + version "1.22.8" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== dependencies: - is-core-module "^2.12.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" resolve@^2.0.0-next.4: - version "2.0.0-next.4" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.4.tgz#3d37a113d6429f496ec4752d2a2e58efb1fd4660" - integrity sha512-iMDbmAWtfU+MHpxt/I5iWI7cY6YVEZUQ3MBgPQ++XD1PELuJHIl82xBmObyP2KyQmkNB2dsqF7seoQQiAn5yDQ== + version "2.0.0-next.5" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-2.0.0-next.5.tgz#6b0ec3107e671e52b68cd068ef327173b90dc03c" + integrity sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA== dependencies: - is-core-module "^2.9.0" + is-core-module "^2.13.0" path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" From 495bb30a4435202bc8d90b585db0cefbe1c9be7a Mon Sep 17 00:00:00 2001 From: Elena Stoeva <59341489+ElenaStoeva@users.noreply.github.com> Date: Fri, 2 Aug 2024 11:47:00 +0100 Subject: [PATCH 5/7] [Console Monaco] Improve highlighting for status codes in multiple responses (#189210) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes https://github.com/elastic/kibana/issues/184010 ## Summary This PR adds color badges for the status codes in the output panel when there are multiple responses. https://github.com/user-attachments/assets/be07b34d-7d04-4448-bf5d-b0d6fa36f2d7 **How to test:** Send the following requests at once (try arranging them in different orders): Success badge 🟢 : `GET _search` Client error (warning) badge 🟡 : `GET _test` Server error (danger) badge 🔴 : ``` PUT /library/_bulk?refresh {"index":{"_id":"Leviathan Wakes"}} {"name":"Leviathan Wakes","author":"James S.A. Corey","release_date":"2011-06-02","page_count":561} ``` ^ This request should usually succeed and it was fixed in https://github.com/elastic/kibana/pull/188552, but these changes aren't in this branch yet so the request still fails. I couldn't find another example that returns a 5** status code. Note: AFAIK Es currently only uses 2**, 4**, and 5** status codes (200 OK, 201 Created, 202 Accepted, 204 No Content, 400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found, 409 Conflict, 429 Too Many Requests, 500 Internal Server Error, 503 Service Unavailable). Practically only the success, warning, and danger badges will be used, but added badges for the rest status codes in case they are added in Es. --- .../src/console/lexer_rules/console_output.ts | 6 +- packages/kbn-monaco/src/console/theme.ts | 16 +- .../editor/monaco/monaco_editor_output.tsx | 10 + .../editor/monaco/utils/constants.ts | 9 + .../containers/editor/monaco/utils/index.ts | 11 +- .../status_code_decoration_utils.test.ts | 197 ++++++++++++++++++ .../utils/status_code_decoration_utils.ts | 65 ++++++ src/plugins/console/public/styles/_app.scss | 44 +++- 8 files changed, 346 insertions(+), 12 deletions(-) create mode 100644 src/plugins/console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.test.ts create mode 100644 src/plugins/console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.ts diff --git a/packages/kbn-monaco/src/console/lexer_rules/console_output.ts b/packages/kbn-monaco/src/console/lexer_rules/console_output.ts index 8209820930910..697a594d0cd19 100644 --- a/packages/kbn-monaco/src/console/lexer_rules/console_output.ts +++ b/packages/kbn-monaco/src/console/lexer_rules/console_output.ts @@ -35,8 +35,10 @@ export const consoleOutputLexerRules: monaco.languages.IMonarchLanguage = { matchTokensWithEOL('status.success', /\b2\d{2}(?: \w+)*$/, 'root'), // Redirection messages (status codes 300 – 399) matchTokensWithEOL('status.redirect', /\b3\d{2}(?: \w+)*$/, 'root'), - // Client and server error responses (status codes 400 – 599) - matchTokensWithEOL('status.error', /\b[4-5]\d{2}(?: \w+)*$/, 'root'), + // Client error responses (status codes 400 – 499) + matchTokensWithEOL('status.warning', /\b4\d{2}(?: \w+)*$/, 'root'), + // Server error responses (status codes 500 – 599) + matchTokensWithEOL('status.error', /\b5\d{2}(?: \w+)*$/, 'root'), ], }, }; diff --git a/packages/kbn-monaco/src/console/theme.ts b/packages/kbn-monaco/src/console/theme.ts index 3a90771354a53..4c9d4c2e03885 100644 --- a/packages/kbn-monaco/src/console/theme.ts +++ b/packages/kbn-monaco/src/console/theme.ts @@ -39,23 +39,23 @@ export const buildConsoleTheme = (): monaco.editor.IStandaloneThemeData => { ), ...buildRuleGroup( ['status.info'], - makeHighContrastColor(euiThemeVars.euiColorWarningText)(background), - true + makeHighContrastColor(euiThemeVars.euiTextColor)(background) ), ...buildRuleGroup( ['status.success'], - makeHighContrastColor(euiThemeVars.euiColorSuccessText)(background), - true + makeHighContrastColor(euiThemeVars.euiTextColor)(euiThemeVars.euiColorSuccess) ), ...buildRuleGroup( ['status.redirect'], - makeHighContrastColor(euiThemeVars.euiColorWarningText)(background), - true + makeHighContrastColor(euiThemeVars.euiTextColor)(background) + ), + ...buildRuleGroup( + ['status.warning'], + makeHighContrastColor(euiThemeVars.euiTextColor)(euiThemeVars.euiColorWarning) ), ...buildRuleGroup( ['status.error'], - makeHighContrastColor(euiThemeVars.euiColorDangerText)(background), - true + makeHighContrastColor('#FFFFFF')(euiThemeVars.euiColorDanger) ), ...buildRuleGroup(['method'], makeHighContrastColor(methodTextColor)(background)), ...buildRuleGroup(['url'], makeHighContrastColor(urlTextColor)(background)), diff --git a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_output.tsx b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_output.tsx index dfbcfd7e4aa75..e1a8a692f40db 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_output.tsx +++ b/src/plugins/console/public/application/containers/editor/monaco/monaco_editor_output.tsx @@ -14,6 +14,7 @@ import Protobuf from 'pbf'; import { i18n } from '@kbn/i18n'; import { EuiScreenReaderOnly } from '@elastic/eui'; import { CONSOLE_THEME_ID, CONSOLE_OUTPUT_LANG_ID, monaco } from '@kbn/monaco'; +import { getStatusCodeDecorations } from './utils'; import { useEditorReadContext, useRequestReadContext } from '../../../contexts'; import { convertMapboxVectorTileToJson } from '../legacy/console_editor/mapbox_vector_tile'; import { @@ -33,10 +34,12 @@ export const MonacoEditorOutput: FunctionComponent = () => { const [mode, setMode] = useState('text'); const divRef = useRef(null); const { setupResizeChecker, destroyResizeChecker } = useResizeCheckerUtils(); + const lineDecorations = useRef(null); const editorDidMountCallback = useCallback( (editor: monaco.editor.IStandaloneCodeEditor) => { setupResizeChecker(divRef.current!, editor); + lineDecorations.current = editor.createDecorationsCollection(); }, [setupResizeChecker] ); @@ -46,6 +49,8 @@ export const MonacoEditorOutput: FunctionComponent = () => { }, [destroyResizeChecker]); useEffect(() => { + // Clean up any existing line decorations + lineDecorations.current?.clear(); if (data) { const isMultipleRequest = data.length > 1; setMode( @@ -73,6 +78,11 @@ export const MonacoEditorOutput: FunctionComponent = () => { }) .join('\n') ); + if (isMultipleRequest) { + // If there are multiple responses, add decorations for their status codes + const decorations = getStatusCodeDecorations(data); + lineDecorations.current?.set(decorations); + } } else { setValue(''); } diff --git a/src/plugins/console/public/application/containers/editor/monaco/utils/constants.ts b/src/plugins/console/public/application/containers/editor/monaco/utils/constants.ts index 5d6088653f243..0f4664be48994 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/utils/constants.ts +++ b/src/plugins/console/public/application/containers/editor/monaco/utils/constants.ts @@ -13,6 +13,15 @@ import { i18n } from '@kbn/i18n'; */ export const SELECTED_REQUESTS_CLASSNAME = 'console__monaco_editor__selectedRequests'; +/* + * CSS class names used for the styling of multiple-response status codes + */ +export const PRIMARY_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--primary'; +export const SUCCESS_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--success'; +export const DEFAULT_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--default'; +export const WARNING_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--warning'; +export const DANGER_STATUS_BADGE_CLASSNAME = 'monaco__status_badge--danger'; + export const whitespacesRegex = /\s+/; export const newLineRegex = /\n/; export const slashesRegex = /\/+/; diff --git a/src/plugins/console/public/application/containers/editor/monaco/utils/index.ts b/src/plugins/console/public/application/containers/editor/monaco/utils/index.ts index 069f99552222a..0997aa682b630 100644 --- a/src/plugins/console/public/application/containers/editor/monaco/utils/index.ts +++ b/src/plugins/console/public/application/containers/editor/monaco/utils/index.ts @@ -6,7 +6,15 @@ * Side Public License, v 1. */ -export { AutocompleteType, SELECTED_REQUESTS_CLASSNAME } from './constants'; +export { + AutocompleteType, + SELECTED_REQUESTS_CLASSNAME, + SUCCESS_STATUS_BADGE_CLASSNAME, + WARNING_STATUS_BADGE_CLASSNAME, + PRIMARY_STATUS_BADGE_CLASSNAME, + DEFAULT_STATUS_BADGE_CLASSNAME, + DANGER_STATUS_BADGE_CLASSNAME, +} from './constants'; export { getRequestStartLineNumber, getRequestEndLineNumber, @@ -25,3 +33,4 @@ export { shouldTriggerSuggestions, } from './autocomplete_utils'; export { getLineTokens, containsUrlParams } from './tokens_utils'; +export { getStatusCodeDecorations } from './status_code_decoration_utils'; diff --git a/src/plugins/console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.test.ts b/src/plugins/console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.test.ts new file mode 100644 index 0000000000000..c65f55c2fed35 --- /dev/null +++ b/src/plugins/console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.test.ts @@ -0,0 +1,197 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +import { getStatusCodeDecorations } from './status_code_decoration_utils'; +import { + SUCCESS_STATUS_BADGE_CLASSNAME, + WARNING_STATUS_BADGE_CLASSNAME, + DANGER_STATUS_BADGE_CLASSNAME, +} from './constants'; +import { RequestResult } from '../../../../hooks/use_send_current_request/send_request'; + +describe('getStatusCodeDecorations', () => { + it('correctly returns all decorations on full data', () => { + // Sample multiple-response data returned from ES: + // 1 # GET _search 200 OK + // 2 { + // 3 "took": 1, + // 4 "timed_out": false, + // 5 "hits": { + // 6 "total": { + // 7 "value": 0, + // 8 "relation": "eq" + // 9 } + // 10 } + // 11 } + // 12 # GET _test 400 Bad Request + // 13 { + // 14 "error": { + // 15 "root_cause": [], + // 16 "status": 400 + // 17 } + // 18 # PUT /library/_bulk 500 Internal Server Error + // 19 { + // 20 "error": { + // 21 "root_cause": [], + // 22 "status": 500 + // 23 } + const SAMPLE_COMPLETE_DATA: RequestResult[] = [ + { + response: { + timeMs: 50, + statusCode: 200, + statusText: 'OK', + contentType: 'application/json', + value: + '# GET _search 200 OK\n{\n"took": 1,\n"timed_out": false,\n"hits": {\n"total": {\n"value": 0,\n"relation": "eq"\n}\n}\n}', + }, + request: { + data: '', + method: 'GET', + path: '_search', + }, + }, + { + response: { + timeMs: 22, + statusCode: 400, + statusText: 'Bad Request', + contentType: 'application/json', + value: '# GET _test 400 Bad Request\n{\n"error": {\n"root_cause": [],\n"status": 400\n}', + }, + request: { + data: '', + method: 'GET', + path: '_test', + }, + }, + { + response: { + timeMs: 23, + statusCode: 500, + statusText: 'Internal Server Error', + contentType: 'application/json', + value: + '# PUT /library/_bulk 500 Internal Server Error\n{\n"error": {\n"root_cause": [],\n"status": 500\n}', + }, + request: { + data: '', + method: 'PUT', + path: '/library/_bulk?refresh', + }, + }, + ]; + + const EXPECTED_DECORATIONS = [ + { + range: { + endColumn: 21, + endLineNumber: 1, + startColumn: 15, + startLineNumber: 1, + }, + options: { + inlineClassName: SUCCESS_STATUS_BADGE_CLASSNAME, + }, + }, + { + range: { + endColumn: 28, + endLineNumber: 12, + startColumn: 13, + startLineNumber: 12, + }, + options: { + inlineClassName: WARNING_STATUS_BADGE_CLASSNAME, + }, + }, + { + range: { + endColumn: 47, + endLineNumber: 18, + startColumn: 22, + startLineNumber: 18, + }, + options: { + inlineClassName: DANGER_STATUS_BADGE_CLASSNAME, + }, + }, + ]; + + expect(getStatusCodeDecorations(SAMPLE_COMPLETE_DATA)).toEqual(EXPECTED_DECORATIONS); + }); + + it('only returns decorations for data with complete status code and text', () => { + // This sample data is same as in previous test but some of it has incomplete status code or status text + const SAMPLE_INCOMPLETE_DATA: RequestResult[] = [ + { + response: { + timeMs: 50, + // @ts-ignore + statusCode: undefined, + statusText: 'OK', + contentType: 'application/json', + value: + '# GET _search OK\n{\n"took": 1,\n"timed_out": false,\n"hits": {\n"total": {\n"value": 0,\n"relation": "eq"\n}\n}\n}', + }, + request: { + data: '', + method: 'GET', + path: '_search', + }, + }, + { + response: { + timeMs: 22, + statusCode: 400, + statusText: 'Bad Request', + contentType: 'application/json', + value: '# GET _test 400 Bad Request\n{\n"error": {\n"root_cause": [],\n"status": 400\n}', + }, + request: { + data: '', + method: 'GET', + path: '_test', + }, + }, + { + response: { + timeMs: 23, + // @ts-ignore + statusCode: undefined, + // @ts-ignore + statusText: undefined, + contentType: 'application/json', + value: '# PUT /library/_bulk\n{\n"error": {\n"root_cause": [],\n"status": 500\n}', + }, + request: { + data: '', + method: 'PUT', + path: '/library/_bulk?refresh', + }, + }, + ]; + + // Only the second response has complete status code and text + const EXPECTED_DECORATIONS = [ + { + range: { + endColumn: 28, + endLineNumber: 12, + startColumn: 13, + startLineNumber: 12, + }, + options: { + inlineClassName: WARNING_STATUS_BADGE_CLASSNAME, + }, + }, + ]; + + expect(getStatusCodeDecorations(SAMPLE_INCOMPLETE_DATA)).toEqual(EXPECTED_DECORATIONS); + }); +}); diff --git a/src/plugins/console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.ts b/src/plugins/console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.ts new file mode 100644 index 0000000000000..3a0724c874ca5 --- /dev/null +++ b/src/plugins/console/public/application/containers/editor/monaco/utils/status_code_decoration_utils.ts @@ -0,0 +1,65 @@ +/* + * 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 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 or the Server + * Side Public License, v 1. + */ + +import { monaco } from '@kbn/monaco'; +import { RequestResult } from '../../../../hooks/use_send_current_request/send_request'; +import { + DEFAULT_STATUS_BADGE_CLASSNAME, + SUCCESS_STATUS_BADGE_CLASSNAME, + PRIMARY_STATUS_BADGE_CLASSNAME, + WARNING_STATUS_BADGE_CLASSNAME, + DANGER_STATUS_BADGE_CLASSNAME, +} from './constants'; + +const getStatusCodeClassName = (statusCode: number) => { + if (statusCode <= 199) { + return DEFAULT_STATUS_BADGE_CLASSNAME; + } + if (statusCode <= 299) { + return SUCCESS_STATUS_BADGE_CLASSNAME; + } + if (statusCode <= 399) { + return PRIMARY_STATUS_BADGE_CLASSNAME; + } + if (statusCode <= 499) { + return WARNING_STATUS_BADGE_CLASSNAME; + } + return DANGER_STATUS_BADGE_CLASSNAME; +}; + +export const getStatusCodeDecorations = (data: RequestResult[]) => { + const decorations: monaco.editor.IModelDeltaDecoration[] = []; + let lastResponseEndLine = 0; + + data.forEach(({ response }) => { + if (response?.value) { + const totalStatus = + response.statusCode && response.statusText + ? response.statusCode + ' ' + response.statusText + : ''; + const startColumn = (response.value as string).indexOf(totalStatus) + 1; + if (totalStatus && startColumn !== 0) { + const range = { + startLineNumber: lastResponseEndLine + 1, + startColumn, + endLineNumber: lastResponseEndLine + 1, + endColumn: startColumn + totalStatus.length, + }; + decorations.push({ + range, + options: { + inlineClassName: getStatusCodeClassName(response.statusCode), + }, + }); + } + lastResponseEndLine += (response.value as string).split(/\\n|\n/).length; + } + }); + + return decorations; +}; diff --git a/src/plugins/console/public/styles/_app.scss b/src/plugins/console/public/styles/_app.scss index 161fd913c32ae..fdeaf67963fa1 100644 --- a/src/plugins/console/public/styles/_app.scss +++ b/src/plugins/console/public/styles/_app.scss @@ -133,10 +133,52 @@ .console__monaco_editor__selectedRequests { background: transparentize($euiColorPrimary, .9); } + /* - * The z-index for the autocomplete suggestions popup + * The styling for the multiple-response status code decorations */ +%monaco__status_badge { + font-family: $euiFontFamily; + font-size: $euiFontSizeS; + font-weight: $euiFontWeightMedium; + line-height: $euiLineHeight; + padding: calc($euiSizeXS / 2) $euiSizeXS; + display: inline-block; + border-radius: calc($euiBorderRadius / 2); + white-space: nowrap; + vertical-align: top; + cursor: default; + max-width: 100%; +} + +.monaco__status_badge--primary { + @extend %monaco__status_badge; + background-color: $euiColorVis1; +} + +.monaco__status_badge--success { + @extend %monaco__status_badge; + background-color: $euiColorSuccess; +} + +.monaco__status_badge--default { + @extend %monaco__status_badge; + background-color: $euiColorLightShade; +} + +.monaco__status_badge--warning { + @extend %monaco__status_badge; + background-color: $euiColorWarning; +} + +.monaco__status_badge--danger { + @extend %monaco__status_badge; + background-color: $euiColorDanger; +} +/* + * The z-index for the autocomplete suggestions popup + */ .kibanaCodeEditor .monaco-editor .suggest-widget { // the value needs to be above the z-index of the resizer bar z-index: $euiZLevel1 + 2; From 02510bae9e5fdb5d1fd535073f94e9d98d23d0d1 Mon Sep 17 00:00:00 2001 From: Navarone Feekery <13634519+navarone-feekery@users.noreply.github.com> Date: Fri, 2 Aug 2024 12:48:05 +0200 Subject: [PATCH 6/7] [Search] Fix Jira connector DLS (#189781) Jira connector DLS restrictions for Server and Data Center we removed in 8.13 for connector clients (https://github.com/elastic/connectors/pull/2108), but this change wasn't propagated to native connectors. This PR removes that restriction so native Jira connectors can use DLS regardless of source type. --- packages/kbn-search-connectors/types/native_connectors.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/kbn-search-connectors/types/native_connectors.ts b/packages/kbn-search-connectors/types/native_connectors.ts index 30ce2c790a2ec..4f95f0c9003fc 100644 --- a/packages/kbn-search-connectors/types/native_connectors.ts +++ b/packages/kbn-search-connectors/types/native_connectors.ts @@ -2017,12 +2017,7 @@ export const NATIVE_CONNECTOR_DEFINITIONS: Record Date: Fri, 2 Aug 2024 13:23:52 +0200 Subject: [PATCH 7/7] [Spaces] Added additional tests for space next route navigation (#189497) ## Summary Added additional tests for space next route navigation with default route, specifically: - `defaultRoute` with and without hash - `defaultRoute` with and without search - `defaultRoute` check for not navigating outside of space base url ### Checklist - [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios __Fixes: https://github.com/elastic/kibana/issues/189481__ --- .../spaces/server/routes/views/index.test.ts | 178 ++++++++---------- .../spaces/server/routes/views/index.ts | 1 + .../functional/apps/spaces/enter_space.ts | 38 +++- 3 files changed, 118 insertions(+), 99 deletions(-) diff --git a/x-pack/plugins/spaces/server/routes/views/index.test.ts b/x-pack/plugins/spaces/server/routes/views/index.test.ts index cb93a62256ed2..b87bfe86c022a 100644 --- a/x-pack/plugins/spaces/server/routes/views/index.test.ts +++ b/x-pack/plugins/spaces/server/routes/views/index.test.ts @@ -107,72 +107,63 @@ describe('Enter Space view routes', () => { }); }); - it('correctly enters space default route.', async () => { - const request = httpServerMock.createKibanaRequest(); - const responseFactory = httpResourcesMock.createResponseFactory(); - const contextMock = coreMock.createRequestHandlerContext(); - - contextMock.uiSettings.client.get.mockResolvedValue('/home'); + const testCase = ( + description: string, + { + query, + defaultRoute, + expectedLocation, + }: { query?: Record; defaultRoute?: string; expectedLocation: string } + ) => { + it(description, async () => { + const request = httpServerMock.createKibanaRequest({ + query, + }); - await routeHandler( - { core: contextMock } as unknown as RequestHandlerContext, - request, - responseFactory - ); + const responseFactory = httpResourcesMock.createResponseFactory(); + const contextMock = coreMock.createRequestHandlerContext(); + contextMock.uiSettings.client.get.mockResolvedValue(defaultRoute); - expect(responseFactory.redirected).toHaveBeenCalledWith({ - headers: { location: '/mock-server-basepath/home' }, - }); - }); + await routeHandler( + { core: contextMock } as unknown as RequestHandlerContext, + request, + responseFactory + ); - it('correctly enters space with specified route.', async () => { - const nextRoute = '/app/management/kibana/objects'; - const request = httpServerMock.createKibanaRequest({ - query: { - next: nextRoute, - }, + expect(responseFactory.redirected).toHaveBeenCalledWith({ + headers: { location: expectedLocation }, + }); }); + }; - const responseFactory = httpResourcesMock.createResponseFactory(); - const contextMock = coreMock.createRequestHandlerContext(); - - await routeHandler( - { core: contextMock } as unknown as RequestHandlerContext, - request, - responseFactory - ); - - expect(responseFactory.redirected).toHaveBeenCalledWith({ - headers: { location: `/mock-server-basepath${nextRoute}` }, - }); + testCase('correctly enters space default route.', { + defaultRoute: '/home', + expectedLocation: '/mock-server-basepath/home', }); - it('correctly enters space with specified route without leading slash.', async () => { - const nextRoute = 'app/management/kibana/objects'; - const request = httpServerMock.createKibanaRequest({ - query: { - next: nextRoute, - }, - }); - - const responseFactory = httpResourcesMock.createResponseFactory(); - const contextMock = coreMock.createRequestHandlerContext(); - - await routeHandler( - { core: contextMock } as unknown as RequestHandlerContext, - request, - responseFactory - ); + testCase('correctly enters space with specified route.', { + query: { + next: '/app/management/kibana/objects', + }, + expectedLocation: '/mock-server-basepath/app/management/kibana/objects', + }); - expect(responseFactory.redirected).toHaveBeenCalledWith({ - headers: { location: `/mock-server-basepath/${nextRoute}` }, - }); + testCase('correctly enters space with specified route without leading slash.', { + query: { + next: 'app/management/kibana/objects', + }, + expectedLocation: '/mock-server-basepath/app/management/kibana/objects', }); - it('correctly enters space and normalizes specified route.', async () => { - const responseFactory = httpResourcesMock.createResponseFactory(); - const contextMock = coreMock.createRequestHandlerContext(); + testCase('correctly enters space with default route if specified route is not relative.', { + query: { + next: 'http://evil.com/mock-server-basepath/app/kibana', + }, + defaultRoute: '/home', + expectedLocation: '/mock-server-basepath/home', + }); + describe('specified route normalization', () => { for (const { query, expectedLocation } of [ { query: { @@ -205,56 +196,47 @@ describe('Enter Space view routes', () => { expectedLocation: '/mock-server-basepath/app/management/kibana/objects?initialQuery=type:(visualization)', }, + ]) { + testCase(`url ${query.next}`, { query, expectedLocation }); + } + }); + + describe('default route', () => { + for (const { defaultRoute, expectedLocation, query, testCaseName } of [ { - query: { - next: '/app/discover#/view/uuid', - }, - expectedLocation: '/mock-server-basepath/app/discover#/view/uuid', + defaultRoute: '/home', + expectedLocation: '/mock-server-basepath/home', + testCaseName: 'correctly enters space with default route.', }, { - query: { - next: '/app/discover?initialQuery=type:(visualization)#/view/uuid', - }, + defaultRoute: '/home', + expectedLocation: '/mock-server-basepath/home', + testCaseName: 'correctly enters space with default route if specified url is empty string.', + query: { next: '' }, + }, + { + defaultRoute: '/home/#view', + expectedLocation: '/mock-server-basepath/home/#view', + testCaseName: 'correctly enters space with default route preserving url hash.', + }, + { + defaultRoute: '/home?initialQuery=type:(visualization)', + expectedLocation: '/mock-server-basepath/home?initialQuery=type:(visualization)', + testCaseName: 'correctly enters space with default route preserving url search.', + }, + { + defaultRoute: '/app/discover?initialQuery=type:(visualization)#/view/uuid', expectedLocation: '/mock-server-basepath/app/discover?initialQuery=type:(visualization)#/view/uuid', + testCaseName: 'correctly enters space with default route preserving url search and hash.', + }, + { + defaultRoute: '../../app/../app/management/kibana/objects', + expectedLocation: '/mock-server-basepath/app/management/kibana/objects', + testCaseName: 'correctly enters space with default route normalizing url.', }, ]) { - const request = httpServerMock.createKibanaRequest({ - query, - }); - await routeHandler( - { core: contextMock } as unknown as RequestHandlerContext, - request, - responseFactory - ); - - expect(responseFactory.redirected).toHaveBeenCalledWith({ - headers: { location: expectedLocation }, - }); - - responseFactory.redirected.mockClear(); + testCase(testCaseName, { query, defaultRoute, expectedLocation }); } }); - - it('correctly enters space with default route if specificed route is not relative.', async () => { - const request = httpServerMock.createKibanaRequest({ - query: { - next: 'http://evil.com/mock-server-basepath/app/kibana', - }, - }); - - const responseFactory = httpResourcesMock.createResponseFactory(); - const contextMock = coreMock.createRequestHandlerContext(); - contextMock.uiSettings.client.get.mockResolvedValue('/home'); - - await routeHandler( - { core: contextMock } as unknown as RequestHandlerContext, - request, - responseFactory - ); - - expect(responseFactory.redirected).toHaveBeenCalledWith({ - headers: { location: '/mock-server-basepath/home' }, - }); - }); }); diff --git a/x-pack/plugins/spaces/server/routes/views/index.ts b/x-pack/plugins/spaces/server/routes/views/index.ts index 2b4cdd9dbcf1f..ab06b17374f13 100644 --- a/x-pack/plugins/spaces/server/routes/views/index.ts +++ b/x-pack/plugins/spaces/server/routes/views/index.ts @@ -44,6 +44,7 @@ export function initSpacesViewsRoutes(deps: ViewRouteDeps) { // need to get reed of ../../ to make sure we will not be out of space basePath const normalizedRoute = new URL(route, 'https://localhost'); + // preserving of the hash is important for the navigation to work correctly with default route return response.redirected({ headers: { location: `${basePath}${normalizedRoute.pathname}${normalizedRoute.search}${normalizedRoute.hash}`, diff --git a/x-pack/test/functional/apps/spaces/enter_space.ts b/x-pack/test/functional/apps/spaces/enter_space.ts index 85cf3b39cf09f..4cff39e05b413 100644 --- a/x-pack/test/functional/apps/spaces/enter_space.ts +++ b/x-pack/test/functional/apps/spaces/enter_space.ts @@ -110,10 +110,37 @@ export default function enterSpaceFunctionalTests({ const anchorElement = await PageObjects.spaceSelector.getSpaceCardAnchor(spaceId); const path = await anchorElement.getAttribute('href'); - const pathWithNextRoute = `${path}?next=/app/management/kibana/objects?initialQuery=type:(visualization)#/view`; + const pathWithNextRoute = `${path}?next=/app/management/kibana/objects?initialQuery=type:(visualization)#/view/uuid`; await browser.navigateTo(pathWithNextRoute); + await PageObjects.spaceSelector.expectRoute( + spaceId, + '/app/management/kibana/objects?initialQuery=type%3A(visualization)#/view/uuid' + ); + }); + + it('allows user to navigate to different space with default route preserving url hash and search', async () => { + const spaceId = 'another-space'; + + await kibanaServer.uiSettings.replace( + { + defaultRoute: '/app/management/kibana/objects?initialQuery=type:(visualization)#/view', + buildNum: 8467, + 'dateFormat:tz': 'UTC', + }, + { space: 'another-space' } + ); + + await PageObjects.security.login(undefined, undefined, { + expectSpaceSelector: true, + }); + + const anchorElement = await PageObjects.spaceSelector.getSpaceCardAnchor(spaceId); + const path = await anchorElement.getAttribute('href'); + + await browser.navigateTo(path!); + await PageObjects.spaceSelector.expectRoute( spaceId, '/app/management/kibana/objects?initialQuery=type%3A(visualization)#/view' @@ -142,6 +169,15 @@ export default function enterSpaceFunctionalTests({ it('falls back to the default home page if provided next route is malformed', async () => { const spaceId = 'another-space'; + await kibanaServer.uiSettings.replace( + { + defaultRoute: '/app/canvas', + buildNum: 8467, + 'dateFormat:tz': 'UTC', + }, + { space: 'another-space' } + ); + await PageObjects.security.login(undefined, undefined, { expectSpaceSelector: true, });