diff --git a/.buildkite/pipelines/on_merge.yml b/.buildkite/pipelines/on_merge.yml index 2963f1c9ba1d6b..8b00db428a7130 100644 --- a/.buildkite/pipelines/on_merge.yml +++ b/.buildkite/pipelines/on_merge.yml @@ -254,7 +254,7 @@ steps: - command: .buildkite/scripts/steps/check_types.sh label: 'Check Types' agents: - queue: n2-2-spot + queue: n2-4-spot timeout_in_minutes: 60 retry: automatic: diff --git a/.buildkite/scripts/steps/archive_so_migration_snapshot.sh b/.buildkite/scripts/steps/archive_so_migration_snapshot.sh index 3cff06507bc6d0..3db3da975b41b9 100755 --- a/.buildkite/scripts/steps/archive_so_migration_snapshot.sh +++ b/.buildkite/scripts/steps/archive_so_migration_snapshot.sh @@ -7,7 +7,7 @@ SO_MIGRATIONS_SNAPSHOT_FOLDER=kibana-so-types-snapshots SNAPSHOT_FILE_PATH="${1:-target/plugin_so_types_snapshot.json}" echo "--- Creating snapshot of Saved Object migration info" -node scripts/snapshot_plugin_types --outputPath "$SNAPSHOT_FILE_PATH" +node scripts/snapshot_plugin_types snapshot --outputPath "$SNAPSHOT_FILE_PATH" echo "--- Uploading as ${BUILDKITE_COMMIT}.json" SNAPSHOT_PATH="${SO_MIGRATIONS_SNAPSHOT_FOLDER}/${BUILDKITE_COMMIT}.json" diff --git a/.buildkite/scripts/steps/check_types.sh b/.buildkite/scripts/steps/check_types.sh index 45778427741c19..94c28c9b47d9bf 100755 --- a/.buildkite/scripts/steps/check_types.sh +++ b/.buildkite/scripts/steps/check_types.sh @@ -7,4 +7,4 @@ source .buildkite/scripts/common/util.sh .buildkite/scripts/bootstrap.sh echo --- Check Types -node --max-old-space-size=4096 scripts/type_check +node scripts/type_check diff --git a/.buildkite/scripts/steps/checks/precommit_hook.sh b/.buildkite/scripts/steps/checks/precommit_hook.sh index 8fa51a4f4d23ce..147569b595dc93 100755 --- a/.buildkite/scripts/steps/checks/precommit_hook.sh +++ b/.buildkite/scripts/steps/checks/precommit_hook.sh @@ -19,8 +19,4 @@ If you want, you can still manually install the pre-commit hook locally by runni node scripts/precommit_hook.js \ --ref HEAD~1..HEAD \ --max-files 200 \ - --verbose \ - --fix \ - --no-stage # we have to disable staging or check_for_changed_files won't see the changes - -check_for_changed_files 'node scripts/precommit_hook.js --ref HEAD~1..HEAD --fix' true + --verbose diff --git a/.eslintrc.js b/.eslintrc.js index 4bc7e1f760277e..82193a7e2ecb78 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -928,17 +928,16 @@ module.exports = { }, { files: [ - 'x-pack/plugins/aiops/**/!(*.test.tsx).tsx', - 'x-pack/plugins/apm/**/!(*.test.tsx).tsx', - 'x-pack/plugins/exploratory_view/**/!(*.test.tsx).tsx', - 'x-pack/plugins/infra/**/!(*.test.tsx).tsx', - 'x-pack/plugins/observability/**/!(*.test.tsx)', - 'x-pack/plugins/observability_ai_assistant/**/!(*.test.tsx).tsx', - 'x-pack/plugins/observability_onboarding/**/!(*.test.tsx).tsx', - 'x-pack/plugins/observability_shared/**/!(*.test.tsx).tsx', - 'x-pack/plugins/profiling/**/!(*.test.tsx).tsx', - 'x-pack/plugins/synthetics/**/!(*.test.tsx).tsx', - 'x-pack/plugins/ux/**/!(*.test.tsx).tsx', + 'x-pack/plugins/apm/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/exploratory_view/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/infra/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/observability/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/observability_ai_assistant/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/observability_onboarding/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/observability_shared/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/profiling/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/synthetics/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', + 'x-pack/plugins/ux/**/!(*.stories.tsx|*.test.tsx|*.storybook_decorator.tsx|*.mock.tsx)', ], rules: { '@kbn/i18n/strings_should_be_translated_with_i18n': 'warn', diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 87004fdbe855a0..fb41f6d904b10a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -553,7 +553,7 @@ x-pack/plugins/observability @elastic/actionable-observability x-pack/plugins/observability_shared @elastic/observability-ui x-pack/test/security_api_integration/plugins/oidc_provider @elastic/kibana-security test/common/plugins/otel_metrics @elastic/infra-monitoring-ui -packages/kbn-openapi-generator @elastic/security-detection-engine +packages/kbn-openapi-generator @elastic/security-detection-rule-management packages/kbn-optimizer @elastic/kibana-operations packages/kbn-optimizer-webpack-helpers @elastic/kibana-operations packages/kbn-osquery-io-ts-types @elastic/security-asset-management @@ -828,6 +828,7 @@ packages/kbn-web-worker-stub @elastic/kibana-operations packages/kbn-whereis-pkg-cli @elastic/kibana-operations packages/kbn-xstate-utils @elastic/infra-monitoring-ui packages/kbn-yarn-lock-validator @elastic/kibana-operations +packages/kbn-zod-helpers @elastic/security-detection-rule-management #### ## Everything below this line overrides the default assignments for each package. ## Items lower in the file have higher precedence: diff --git a/api_docs/actions.mdx b/api_docs/actions.mdx index c42bfcae295de1..99835df50a0c9c 100644 --- a/api_docs/actions.mdx +++ b/api_docs/actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/actions title: "actions" image: https://source.unsplash.com/400x175/?github description: API docs for the actions plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'actions'] --- import actionsObj from './actions.devdocs.json'; diff --git a/api_docs/advanced_settings.mdx b/api_docs/advanced_settings.mdx index 74784d006edf97..4557c292932bb6 100644 --- a/api_docs/advanced_settings.mdx +++ b/api_docs/advanced_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/advancedSettings title: "advancedSettings" image: https://source.unsplash.com/400x175/?github description: API docs for the advancedSettings plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'advancedSettings'] --- import advancedSettingsObj from './advanced_settings.devdocs.json'; diff --git a/api_docs/aiops.mdx b/api_docs/aiops.mdx index ac3cdaced85564..ae2584e7138c5f 100644 --- a/api_docs/aiops.mdx +++ b/api_docs/aiops.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/aiops title: "aiops" image: https://source.unsplash.com/400x175/?github description: API docs for the aiops plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'aiops'] --- import aiopsObj from './aiops.devdocs.json'; diff --git a/api_docs/alerting.mdx b/api_docs/alerting.mdx index 5fa555574fbcd4..46d523a702c5b4 100644 --- a/api_docs/alerting.mdx +++ b/api_docs/alerting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/alerting title: "alerting" image: https://source.unsplash.com/400x175/?github description: API docs for the alerting plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'alerting'] --- import alertingObj from './alerting.devdocs.json'; diff --git a/api_docs/apm.mdx b/api_docs/apm.mdx index 6cfc3a4b1435ae..656359f0dd01bd 100644 --- a/api_docs/apm.mdx +++ b/api_docs/apm.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apm title: "apm" image: https://source.unsplash.com/400x175/?github description: API docs for the apm plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apm'] --- import apmObj from './apm.devdocs.json'; diff --git a/api_docs/apm_data_access.mdx b/api_docs/apm_data_access.mdx index 482a9c3f27eb01..81d1331278730a 100644 --- a/api_docs/apm_data_access.mdx +++ b/api_docs/apm_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/apmDataAccess title: "apmDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the apmDataAccess plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'apmDataAccess'] --- import apmDataAccessObj from './apm_data_access.devdocs.json'; diff --git a/api_docs/asset_manager.mdx b/api_docs/asset_manager.mdx index e904bbfe0d82b4..ca46cea27297db 100644 --- a/api_docs/asset_manager.mdx +++ b/api_docs/asset_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/assetManager title: "assetManager" image: https://source.unsplash.com/400x175/?github description: API docs for the assetManager plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'assetManager'] --- import assetManagerObj from './asset_manager.devdocs.json'; diff --git a/api_docs/banners.mdx b/api_docs/banners.mdx index e769caf9f3399e..09444f2498fa1b 100644 --- a/api_docs/banners.mdx +++ b/api_docs/banners.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/banners title: "banners" image: https://source.unsplash.com/400x175/?github description: API docs for the banners plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'banners'] --- import bannersObj from './banners.devdocs.json'; diff --git a/api_docs/bfetch.mdx b/api_docs/bfetch.mdx index 8a2b9c44b1670a..3c811164d8349b 100644 --- a/api_docs/bfetch.mdx +++ b/api_docs/bfetch.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/bfetch title: "bfetch" image: https://source.unsplash.com/400x175/?github description: API docs for the bfetch plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'bfetch'] --- import bfetchObj from './bfetch.devdocs.json'; diff --git a/api_docs/canvas.mdx b/api_docs/canvas.mdx index 1ccd24107596a3..f4e49ff2e0f7bd 100644 --- a/api_docs/canvas.mdx +++ b/api_docs/canvas.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/canvas title: "canvas" image: https://source.unsplash.com/400x175/?github description: API docs for the canvas plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'canvas'] --- import canvasObj from './canvas.devdocs.json'; diff --git a/api_docs/cases.mdx b/api_docs/cases.mdx index 75d9bad72b1aba..8ba69e09d531c1 100644 --- a/api_docs/cases.mdx +++ b/api_docs/cases.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cases title: "cases" image: https://source.unsplash.com/400x175/?github description: API docs for the cases plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cases'] --- import casesObj from './cases.devdocs.json'; diff --git a/api_docs/charts.mdx b/api_docs/charts.mdx index df6cdc83b975e1..85e09b71710a52 100644 --- a/api_docs/charts.mdx +++ b/api_docs/charts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/charts title: "charts" image: https://source.unsplash.com/400x175/?github description: API docs for the charts plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'charts'] --- import chartsObj from './charts.devdocs.json'; diff --git a/api_docs/cloud.mdx b/api_docs/cloud.mdx index 256e05177ea71e..67d88b44ffb15f 100644 --- a/api_docs/cloud.mdx +++ b/api_docs/cloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloud title: "cloud" image: https://source.unsplash.com/400x175/?github description: API docs for the cloud plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloud'] --- import cloudObj from './cloud.devdocs.json'; diff --git a/api_docs/cloud_data_migration.mdx b/api_docs/cloud_data_migration.mdx index 14156a569afd4b..7bcea04d9f6d2e 100644 --- a/api_docs/cloud_data_migration.mdx +++ b/api_docs/cloud_data_migration.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDataMigration title: "cloudDataMigration" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDataMigration plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDataMigration'] --- import cloudDataMigrationObj from './cloud_data_migration.devdocs.json'; diff --git a/api_docs/cloud_defend.mdx b/api_docs/cloud_defend.mdx index 04cdb082f1bc1b..731da0ec337a6f 100644 --- a/api_docs/cloud_defend.mdx +++ b/api_docs/cloud_defend.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudDefend title: "cloudDefend" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudDefend plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudDefend'] --- import cloudDefendObj from './cloud_defend.devdocs.json'; diff --git a/api_docs/cloud_experiments.mdx b/api_docs/cloud_experiments.mdx index b643b57c4f6a10..ac827595a5c6d9 100644 --- a/api_docs/cloud_experiments.mdx +++ b/api_docs/cloud_experiments.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudExperiments title: "cloudExperiments" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudExperiments plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudExperiments'] --- import cloudExperimentsObj from './cloud_experiments.devdocs.json'; diff --git a/api_docs/cloud_security_posture.mdx b/api_docs/cloud_security_posture.mdx index 5422cf16e33c23..4781a2c48f9b74 100644 --- a/api_docs/cloud_security_posture.mdx +++ b/api_docs/cloud_security_posture.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/cloudSecurityPosture title: "cloudSecurityPosture" image: https://source.unsplash.com/400x175/?github description: API docs for the cloudSecurityPosture plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'cloudSecurityPosture'] --- import cloudSecurityPostureObj from './cloud_security_posture.devdocs.json'; diff --git a/api_docs/console.mdx b/api_docs/console.mdx index 1e72a2526f580a..31b2367f6e3407 100644 --- a/api_docs/console.mdx +++ b/api_docs/console.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/console title: "console" image: https://source.unsplash.com/400x175/?github description: API docs for the console plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'console'] --- import consoleObj from './console.devdocs.json'; diff --git a/api_docs/content_management.mdx b/api_docs/content_management.mdx index 017bea9ac8c1fd..e26b3bab3e0d1a 100644 --- a/api_docs/content_management.mdx +++ b/api_docs/content_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/contentManagement title: "contentManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the contentManagement plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'contentManagement'] --- import contentManagementObj from './content_management.devdocs.json'; diff --git a/api_docs/controls.mdx b/api_docs/controls.mdx index 95f433ee999397..4c88e8fd0116ba 100644 --- a/api_docs/controls.mdx +++ b/api_docs/controls.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/controls title: "controls" image: https://source.unsplash.com/400x175/?github description: API docs for the controls plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'controls'] --- import controlsObj from './controls.devdocs.json'; diff --git a/api_docs/custom_integrations.mdx b/api_docs/custom_integrations.mdx index 450fa514396304..4a021ac64d20d2 100644 --- a/api_docs/custom_integrations.mdx +++ b/api_docs/custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/customIntegrations title: "customIntegrations" image: https://source.unsplash.com/400x175/?github description: API docs for the customIntegrations plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'customIntegrations'] --- import customIntegrationsObj from './custom_integrations.devdocs.json'; diff --git a/api_docs/dashboard.mdx b/api_docs/dashboard.mdx index a4bbc5d4eab0ad..b8d959e8d72a1c 100644 --- a/api_docs/dashboard.mdx +++ b/api_docs/dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboard title: "dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboard plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboard'] --- import dashboardObj from './dashboard.devdocs.json'; diff --git a/api_docs/dashboard_enhanced.mdx b/api_docs/dashboard_enhanced.mdx index 8d33022a5d6edd..3a96aa54692bff 100644 --- a/api_docs/dashboard_enhanced.mdx +++ b/api_docs/dashboard_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dashboardEnhanced title: "dashboardEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the dashboardEnhanced plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.devdocs.json b/api_docs/data.devdocs.json index 26652d59ae3b05..893f44d9b139a7 100644 --- a/api_docs/data.devdocs.json +++ b/api_docs/data.devdocs.json @@ -4109,7 +4109,7 @@ "\nserializes search source fields (which can later be passed to {@link ISearchStartSearchSource})" ], "signature": [ - "(recurse?: boolean, includeFields?: boolean) => ", + "(recurse?: boolean) => ", { "pluginId": "data", "scope": "common", @@ -4136,21 +4136,6 @@ "deprecated": false, "trackAdoption": false, "isRequired": true - }, - { - "parentPluginId": "data", - "id": "def-public.SearchSource.getSerializedFields.$2", - "type": "boolean", - "tags": [], - "label": "includeFields", - "description": [], - "signature": [ - "boolean" - ], - "path": "src/plugins/data/common/search/search_source/search_source.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true } ], "returnComment": [] @@ -10642,7 +10627,7 @@ "section": "def-common.SearchSourceSearchOptions", "text": "SearchSourceSearchOptions" }, - " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean, includeFields?: boolean) => ", + " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean) => ", { "pluginId": "data", "scope": "common", diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 33b6c63d6f3731..cb5e13d72ac730 100644 --- a/api_docs/data.mdx +++ b/api_docs/data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data title: "data" image: https://source.unsplash.com/400x175/?github description: API docs for the data plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3186 | 33 | 2537 | 22 | +| 3186 | 32 | 2537 | 22 | ## Client diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 2cee7159bd9f0e..0d69c443defc6e 100644 --- a/api_docs/data_query.mdx +++ b/api_docs/data_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-query title: "data.query" image: https://source.unsplash.com/400x175/?github description: API docs for the data.query plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3186 | 33 | 2537 | 22 | +| 3186 | 32 | 2537 | 22 | ## Client diff --git a/api_docs/data_search.devdocs.json b/api_docs/data_search.devdocs.json index 991b3420e09181..a4f3da06d4bd8e 100644 --- a/api_docs/data_search.devdocs.json +++ b/api_docs/data_search.devdocs.json @@ -6738,14 +6738,15 @@ }, { "parentPluginId": "data", - "id": "def-common.AggType.valueType", - "type": "CompoundType", + "id": "def-common.AggType.getValueType", + "type": "Function", "tags": [], - "label": "valueType", + "label": "getValueType", "description": [ "\nThe type the values produced by this agg will have in the final data table.\nIf not specified, the type of the field is used." ], "signature": [ + "((aggConfig: TAggConfig) => ", { "pluginId": "expressions", "scope": "common", @@ -6753,7 +6754,7 @@ "section": "def-common.DatatableColumnType", "text": "DatatableColumnType" }, - " | undefined" + ") | undefined" ], "path": "src/plugins/data/common/search/aggs/agg_type.ts", "deprecated": false, @@ -7308,7 +7309,7 @@ "section": "def-common.SearchSourceSearchOptions", "text": "SearchSourceSearchOptions" }, - " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean, includeFields?: boolean) => ", + " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean) => ", { "pluginId": "data", "scope": "common", @@ -8224,17 +8225,48 @@ }, { "parentPluginId": "data", - "id": "def-common.BaseParamType.valueType", - "type": "Any", + "id": "def-common.BaseParamType.getValueType", + "type": "Function", "tags": [], - "label": "valueType", + "label": "getValueType", "description": [], "signature": [ - "any" + "(aggConfig: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.AggConfig", + "text": "AggConfig" + }, + ") => any" ], "path": "src/plugins/data/common/search/aggs/param_types/base.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "returnComment": [], + "children": [ + { + "parentPluginId": "data", + "id": "def-common.BaseParamType.getValueType.$1", + "type": "Object", + "tags": [], + "label": "aggConfig", + "description": [], + "signature": [ + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.AggConfig", + "text": "AggConfig" + } + ], + "path": "src/plugins/data/common/search/aggs/param_types/base.ts", + "deprecated": false, + "trackAdoption": false + } + ] }, { "parentPluginId": "data", @@ -10708,7 +10740,7 @@ "\nserializes search source fields (which can later be passed to {@link ISearchStartSearchSource})" ], "signature": [ - "(recurse?: boolean, includeFields?: boolean) => ", + "(recurse?: boolean) => ", { "pluginId": "data", "scope": "common", @@ -10735,21 +10767,6 @@ "deprecated": false, "trackAdoption": false, "isRequired": true - }, - { - "parentPluginId": "data", - "id": "def-common.SearchSource.getSerializedFields.$2", - "type": "boolean", - "tags": [], - "label": "includeFields", - "description": [], - "signature": [ - "boolean" - ], - "path": "src/plugins/data/common/search/search_source/search_source.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true } ], "returnComment": [] @@ -25064,12 +25081,13 @@ }, { "parentPluginId": "data", - "id": "def-common.AggTypeConfig.valueType", - "type": "CompoundType", + "id": "def-common.AggTypeConfig.getValueType", + "type": "Function", "tags": [], - "label": "valueType", + "label": "getValueType", "description": [], "signature": [ + "((aggConfig: TAggConfig) => ", { "pluginId": "expressions", "scope": "common", @@ -25077,11 +25095,29 @@ "section": "def-common.DatatableColumnType", "text": "DatatableColumnType" }, - " | undefined" + ") | undefined" ], "path": "src/plugins/data/common/search/aggs/agg_type.ts", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "children": [ + { + "parentPluginId": "data", + "id": "def-common.AggTypeConfig.getValueType.$1", + "type": "Uncategorized", + "tags": [], + "label": "aggConfig", + "description": [], + "signature": [ + "TAggConfig" + ], + "path": "src/plugins/data/common/search/aggs/agg_type.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [] }, { "parentPluginId": "data", @@ -34298,7 +34334,7 @@ "section": "def-common.SearchSourceSearchOptions", "text": "SearchSourceSearchOptions" }, - " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean, includeFields?: boolean) => ", + " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean) => ", { "pluginId": "data", "scope": "common", @@ -38572,7 +38608,15 @@ "section": "def-common.ExpressionAstExpression", "text": "ExpressionAstExpression" }, - "[] | undefined) | undefined; options?: any[] | undefined; valueType?: any; onChange?: ((agg: ", + "[] | undefined) | undefined; options?: any[] | undefined; getValueType?: ((aggConfig: ", + { + "pluginId": "data", + "scope": "common", + "docId": "kibDataSearchPluginApi", + "section": "def-common.AggConfig", + "text": "AggConfig" + }, + ") => any) | undefined; onChange?: ((agg: ", { "pluginId": "data", "scope": "common", diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index e67bb593464332..fe5d5aef222792 100644 --- a/api_docs/data_search.mdx +++ b/api_docs/data_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/data-search title: "data.search" image: https://source.unsplash.com/400x175/?github description: API docs for the data.search plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 3186 | 33 | 2537 | 22 | +| 3186 | 32 | 2537 | 22 | ## Client diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 7c13da6a2e0537..2626d3fd2ed4e4 100644 --- a/api_docs/data_view_editor.mdx +++ b/api_docs/data_view_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewEditor title: "dataViewEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewEditor plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewEditor'] --- import dataViewEditorObj from './data_view_editor.devdocs.json'; diff --git a/api_docs/data_view_field_editor.mdx b/api_docs/data_view_field_editor.mdx index 80cd01c8b648e8..26cfb2a265b40c 100644 --- a/api_docs/data_view_field_editor.mdx +++ b/api_docs/data_view_field_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewFieldEditor title: "dataViewFieldEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewFieldEditor plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewFieldEditor'] --- import dataViewFieldEditorObj from './data_view_field_editor.devdocs.json'; diff --git a/api_docs/data_view_management.mdx b/api_docs/data_view_management.mdx index b847c3db987bbe..d9638e67ad3297 100644 --- a/api_docs/data_view_management.mdx +++ b/api_docs/data_view_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViewManagement title: "dataViewManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViewManagement plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViewManagement'] --- import dataViewManagementObj from './data_view_management.devdocs.json'; diff --git a/api_docs/data_views.mdx b/api_docs/data_views.mdx index c627afa427674c..801ec432a49a73 100644 --- a/api_docs/data_views.mdx +++ b/api_docs/data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataViews title: "dataViews" image: https://source.unsplash.com/400x175/?github description: API docs for the dataViews plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataViews'] --- import dataViewsObj from './data_views.devdocs.json'; diff --git a/api_docs/data_visualizer.mdx b/api_docs/data_visualizer.mdx index 792e51ae384958..f2d3f5c2d7e948 100644 --- a/api_docs/data_visualizer.mdx +++ b/api_docs/data_visualizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/dataVisualizer title: "dataVisualizer" image: https://source.unsplash.com/400x175/?github description: API docs for the dataVisualizer plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dataVisualizer'] --- import dataVisualizerObj from './data_visualizer.devdocs.json'; diff --git a/api_docs/deprecations_by_api.mdx b/api_docs/deprecations_by_api.mdx index bf594e58e2f058..0adb291845434b 100644 --- a/api_docs/deprecations_by_api.mdx +++ b/api_docs/deprecations_by_api.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByApi slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-api title: Deprecated API usage by API description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index 412dacd75f1430..53c5a89bc6ac0f 100644 --- a/api_docs/deprecations_by_plugin.mdx +++ b/api_docs/deprecations_by_plugin.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsByPlugin slug: /kibana-dev-docs/api-meta/deprecated-api-list-by-plugin title: Deprecated API usage by plugin description: A list of deprecated APIs, which plugins are still referencing them, and when they need to be removed by. -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 8eba224669d898..3b779b48aa489c 100644 --- a/api_docs/deprecations_by_team.mdx +++ b/api_docs/deprecations_by_team.mdx @@ -7,7 +7,7 @@ id: kibDevDocsDeprecationsDueByTeam slug: /kibana-dev-docs/api-meta/deprecations-due-by-team title: Deprecated APIs due to be removed, by team description: Lists the teams that are referencing deprecated APIs with a remove by date. -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 4266f43750e26d..66e1e85460a43b 100644 --- a/api_docs/dev_tools.mdx +++ b/api_docs/dev_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/devTools title: "devTools" image: https://source.unsplash.com/400x175/?github description: API docs for the devTools plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'devTools'] --- import devToolsObj from './dev_tools.devdocs.json'; diff --git a/api_docs/discover.devdocs.json b/api_docs/discover.devdocs.json index 70629a5c847179..52a23675fb770b 100644 --- a/api_docs/discover.devdocs.json +++ b/api_docs/discover.devdocs.json @@ -845,6 +845,22 @@ "path": "src/plugins/discover/public/customizations/customization_types/flyout_customization.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "discover", + "id": "def-public.FlyoutCustomization.Content", + "type": "CompoundType", + "tags": [], + "label": "Content", + "description": [], + "signature": [ + "React.ComponentType<", + "FlyoutContentProps", + "> | undefined" + ], + "path": "src/plugins/discover/public/customizations/customization_types/flyout_customization.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false @@ -903,7 +919,8 @@ "docId": "kibSavedSearchPluginApi", "section": "def-public.SavedSearch", "text": "SavedSearch" - } + }, + " | undefined" ], "path": "src/plugins/discover/public/embeddable/types.ts", "deprecated": false, diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index 86418a02e8e240..f0aeff21fc8e6e 100644 --- a/api_docs/discover.mdx +++ b/api_docs/discover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discover title: "discover" image: https://source.unsplash.com/400x175/?github description: API docs for the discover plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discover'] --- import discoverObj from './discover.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 119 | 0 | 76 | 18 | +| 120 | 0 | 77 | 19 | ## Client diff --git a/api_docs/discover_enhanced.mdx b/api_docs/discover_enhanced.mdx index d3e008f27378c0..56afb9e368f2a9 100644 --- a/api_docs/discover_enhanced.mdx +++ b/api_docs/discover_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/discoverEnhanced title: "discoverEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the discoverEnhanced plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'discoverEnhanced'] --- import discoverEnhancedObj from './discover_enhanced.devdocs.json'; diff --git a/api_docs/ecs_data_quality_dashboard.mdx b/api_docs/ecs_data_quality_dashboard.mdx index 4ef74370d60773..71327669251b95 100644 --- a/api_docs/ecs_data_quality_dashboard.mdx +++ b/api_docs/ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ecsDataQualityDashboard title: "ecsDataQualityDashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the ecsDataQualityDashboard plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ecsDataQualityDashboard'] --- import ecsDataQualityDashboardObj from './ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/elastic_assistant.mdx b/api_docs/elastic_assistant.mdx index fa360fe9e02455..1f037158e846c1 100644 --- a/api_docs/elastic_assistant.mdx +++ b/api_docs/elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/elasticAssistant title: "elasticAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the elasticAssistant plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'elasticAssistant'] --- import elasticAssistantObj from './elastic_assistant.devdocs.json'; diff --git a/api_docs/embeddable.mdx b/api_docs/embeddable.mdx index d1b08fc0866c78..ac94364b91ae28 100644 --- a/api_docs/embeddable.mdx +++ b/api_docs/embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddable title: "embeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddable plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddable'] --- import embeddableObj from './embeddable.devdocs.json'; diff --git a/api_docs/embeddable_enhanced.mdx b/api_docs/embeddable_enhanced.mdx index 54f16f7adb7bff..a5c3be24966067 100644 --- a/api_docs/embeddable_enhanced.mdx +++ b/api_docs/embeddable_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/embeddableEnhanced title: "embeddableEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the embeddableEnhanced plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'embeddableEnhanced'] --- import embeddableEnhancedObj from './embeddable_enhanced.devdocs.json'; diff --git a/api_docs/encrypted_saved_objects.mdx b/api_docs/encrypted_saved_objects.mdx index bd6c8cd399b961..e22d1feaac9c28 100644 --- a/api_docs/encrypted_saved_objects.mdx +++ b/api_docs/encrypted_saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/encryptedSavedObjects title: "encryptedSavedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the encryptedSavedObjects plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'encryptedSavedObjects'] --- import encryptedSavedObjectsObj from './encrypted_saved_objects.devdocs.json'; diff --git a/api_docs/enterprise_search.mdx b/api_docs/enterprise_search.mdx index a41b9a7373777c..3d3b4f6d1b8b90 100644 --- a/api_docs/enterprise_search.mdx +++ b/api_docs/enterprise_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/enterpriseSearch title: "enterpriseSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the enterpriseSearch plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'enterpriseSearch'] --- import enterpriseSearchObj from './enterprise_search.devdocs.json'; diff --git a/api_docs/es_ui_shared.mdx b/api_docs/es_ui_shared.mdx index 20400a43564fc6..9dc21b958ebe87 100644 --- a/api_docs/es_ui_shared.mdx +++ b/api_docs/es_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/esUiShared title: "esUiShared" image: https://source.unsplash.com/400x175/?github description: API docs for the esUiShared plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'esUiShared'] --- import esUiSharedObj from './es_ui_shared.devdocs.json'; diff --git a/api_docs/event_annotation.mdx b/api_docs/event_annotation.mdx index 9410e6a30d28f4..f2676a4c1d46a4 100644 --- a/api_docs/event_annotation.mdx +++ b/api_docs/event_annotation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotation title: "eventAnnotation" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotation plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotation'] --- import eventAnnotationObj from './event_annotation.devdocs.json'; diff --git a/api_docs/event_annotation_listing.mdx b/api_docs/event_annotation_listing.mdx index 1cef67c8cd22d7..9a06d75de73f9a 100644 --- a/api_docs/event_annotation_listing.mdx +++ b/api_docs/event_annotation_listing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventAnnotationListing title: "eventAnnotationListing" image: https://source.unsplash.com/400x175/?github description: API docs for the eventAnnotationListing plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventAnnotationListing'] --- import eventAnnotationListingObj from './event_annotation_listing.devdocs.json'; diff --git a/api_docs/event_log.mdx b/api_docs/event_log.mdx index f0add95216cb13..95ebd6fa2943dc 100644 --- a/api_docs/event_log.mdx +++ b/api_docs/event_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/eventLog title: "eventLog" image: https://source.unsplash.com/400x175/?github description: API docs for the eventLog plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'eventLog'] --- import eventLogObj from './event_log.devdocs.json'; diff --git a/api_docs/exploratory_view.mdx b/api_docs/exploratory_view.mdx index d2484f1ff1380b..1656d165569900 100644 --- a/api_docs/exploratory_view.mdx +++ b/api_docs/exploratory_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/exploratoryView title: "exploratoryView" image: https://source.unsplash.com/400x175/?github description: API docs for the exploratoryView plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'exploratoryView'] --- import exploratoryViewObj from './exploratory_view.devdocs.json'; diff --git a/api_docs/expression_error.mdx b/api_docs/expression_error.mdx index b7300c8c03b67e..d584d64623e558 100644 --- a/api_docs/expression_error.mdx +++ b/api_docs/expression_error.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionError title: "expressionError" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionError plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionError'] --- import expressionErrorObj from './expression_error.devdocs.json'; diff --git a/api_docs/expression_gauge.mdx b/api_docs/expression_gauge.mdx index a666621be113e0..801e193c5a5ba8 100644 --- a/api_docs/expression_gauge.mdx +++ b/api_docs/expression_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionGauge title: "expressionGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionGauge plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionGauge'] --- import expressionGaugeObj from './expression_gauge.devdocs.json'; diff --git a/api_docs/expression_heatmap.mdx b/api_docs/expression_heatmap.mdx index 1a63eb4e679fbe..b01ad3cde81f64 100644 --- a/api_docs/expression_heatmap.mdx +++ b/api_docs/expression_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionHeatmap title: "expressionHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionHeatmap plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionHeatmap'] --- import expressionHeatmapObj from './expression_heatmap.devdocs.json'; diff --git a/api_docs/expression_image.mdx b/api_docs/expression_image.mdx index 81dc53afdb9b56..dd4250ab11211f 100644 --- a/api_docs/expression_image.mdx +++ b/api_docs/expression_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionImage title: "expressionImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionImage plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionImage'] --- import expressionImageObj from './expression_image.devdocs.json'; diff --git a/api_docs/expression_legacy_metric_vis.mdx b/api_docs/expression_legacy_metric_vis.mdx index 9c2e1300c4635e..6c2ee232c7404e 100644 --- a/api_docs/expression_legacy_metric_vis.mdx +++ b/api_docs/expression_legacy_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionLegacyMetricVis title: "expressionLegacyMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionLegacyMetricVis plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionLegacyMetricVis'] --- import expressionLegacyMetricVisObj from './expression_legacy_metric_vis.devdocs.json'; diff --git a/api_docs/expression_metric.mdx b/api_docs/expression_metric.mdx index 68607a62884f97..60b60f78453c5d 100644 --- a/api_docs/expression_metric.mdx +++ b/api_docs/expression_metric.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetric title: "expressionMetric" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetric plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetric'] --- import expressionMetricObj from './expression_metric.devdocs.json'; diff --git a/api_docs/expression_metric_vis.mdx b/api_docs/expression_metric_vis.mdx index ae2361d8daad1f..ed834824c1d3fa 100644 --- a/api_docs/expression_metric_vis.mdx +++ b/api_docs/expression_metric_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionMetricVis title: "expressionMetricVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionMetricVis plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionMetricVis'] --- import expressionMetricVisObj from './expression_metric_vis.devdocs.json'; diff --git a/api_docs/expression_partition_vis.mdx b/api_docs/expression_partition_vis.mdx index e5d1c0360dab03..1830c69428321c 100644 --- a/api_docs/expression_partition_vis.mdx +++ b/api_docs/expression_partition_vis.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionPartitionVis title: "expressionPartitionVis" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionPartitionVis plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionPartitionVis'] --- import expressionPartitionVisObj from './expression_partition_vis.devdocs.json'; diff --git a/api_docs/expression_repeat_image.mdx b/api_docs/expression_repeat_image.mdx index 2e0b690306dcc3..cd9794652a6e82 100644 --- a/api_docs/expression_repeat_image.mdx +++ b/api_docs/expression_repeat_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRepeatImage title: "expressionRepeatImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRepeatImage plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRepeatImage'] --- import expressionRepeatImageObj from './expression_repeat_image.devdocs.json'; diff --git a/api_docs/expression_reveal_image.mdx b/api_docs/expression_reveal_image.mdx index d1a7d2f29aa0c9..9137b1a35b656a 100644 --- a/api_docs/expression_reveal_image.mdx +++ b/api_docs/expression_reveal_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionRevealImage title: "expressionRevealImage" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionRevealImage plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionRevealImage'] --- import expressionRevealImageObj from './expression_reveal_image.devdocs.json'; diff --git a/api_docs/expression_shape.mdx b/api_docs/expression_shape.mdx index 0eee910285a14b..7762b38ee80d9e 100644 --- a/api_docs/expression_shape.mdx +++ b/api_docs/expression_shape.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionShape title: "expressionShape" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionShape plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionShape'] --- import expressionShapeObj from './expression_shape.devdocs.json'; diff --git a/api_docs/expression_tagcloud.mdx b/api_docs/expression_tagcloud.mdx index a02749ce4606e1..528c9363ca0172 100644 --- a/api_docs/expression_tagcloud.mdx +++ b/api_docs/expression_tagcloud.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionTagcloud title: "expressionTagcloud" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionTagcloud plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionTagcloud'] --- import expressionTagcloudObj from './expression_tagcloud.devdocs.json'; diff --git a/api_docs/expression_x_y.mdx b/api_docs/expression_x_y.mdx index 4867bd349115fb..983acf8adc3fe5 100644 --- a/api_docs/expression_x_y.mdx +++ b/api_docs/expression_x_y.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressionXY title: "expressionXY" image: https://source.unsplash.com/400x175/?github description: API docs for the expressionXY plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressionXY'] --- import expressionXYObj from './expression_x_y.devdocs.json'; diff --git a/api_docs/expressions.mdx b/api_docs/expressions.mdx index 0aa5927aa8df64..1f18edd06019ca 100644 --- a/api_docs/expressions.mdx +++ b/api_docs/expressions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/expressions title: "expressions" image: https://source.unsplash.com/400x175/?github description: API docs for the expressions plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'expressions'] --- import expressionsObj from './expressions.devdocs.json'; diff --git a/api_docs/features.mdx b/api_docs/features.mdx index 80c21ccacc5211..9596c9c722505e 100644 --- a/api_docs/features.mdx +++ b/api_docs/features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/features title: "features" image: https://source.unsplash.com/400x175/?github description: API docs for the features plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'features'] --- import featuresObj from './features.devdocs.json'; diff --git a/api_docs/field_formats.mdx b/api_docs/field_formats.mdx index c71c4ce700b90a..41734eca9f70f7 100644 --- a/api_docs/field_formats.mdx +++ b/api_docs/field_formats.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fieldFormats title: "fieldFormats" image: https://source.unsplash.com/400x175/?github description: API docs for the fieldFormats plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fieldFormats'] --- import fieldFormatsObj from './field_formats.devdocs.json'; diff --git a/api_docs/file_upload.mdx b/api_docs/file_upload.mdx index f3803da3e90cad..be31ebc6e6cbc0 100644 --- a/api_docs/file_upload.mdx +++ b/api_docs/file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fileUpload title: "fileUpload" image: https://source.unsplash.com/400x175/?github description: API docs for the fileUpload plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fileUpload'] --- import fileUploadObj from './file_upload.devdocs.json'; diff --git a/api_docs/files.mdx b/api_docs/files.mdx index dde9665103033e..a40dfa8fa56577 100644 --- a/api_docs/files.mdx +++ b/api_docs/files.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/files title: "files" image: https://source.unsplash.com/400x175/?github description: API docs for the files plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'files'] --- import filesObj from './files.devdocs.json'; diff --git a/api_docs/files_management.mdx b/api_docs/files_management.mdx index 25f7087e3d9890..1db3ce78576a7f 100644 --- a/api_docs/files_management.mdx +++ b/api_docs/files_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/filesManagement title: "filesManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the filesManagement plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'filesManagement'] --- import filesManagementObj from './files_management.devdocs.json'; diff --git a/api_docs/fleet.mdx b/api_docs/fleet.mdx index 828f1194bea409..20bafef38207d3 100644 --- a/api_docs/fleet.mdx +++ b/api_docs/fleet.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/fleet title: "fleet" image: https://source.unsplash.com/400x175/?github description: API docs for the fleet plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'fleet'] --- import fleetObj from './fleet.devdocs.json'; diff --git a/api_docs/global_search.mdx b/api_docs/global_search.mdx index 853bf579546c97..03556d711ae109 100644 --- a/api_docs/global_search.mdx +++ b/api_docs/global_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/globalSearch title: "globalSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the globalSearch plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'globalSearch'] --- import globalSearchObj from './global_search.devdocs.json'; diff --git a/api_docs/guided_onboarding.mdx b/api_docs/guided_onboarding.mdx index 14d6f3c7f0efa6..42b71820becc3f 100644 --- a/api_docs/guided_onboarding.mdx +++ b/api_docs/guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/guidedOnboarding title: "guidedOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the guidedOnboarding plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'guidedOnboarding'] --- import guidedOnboardingObj from './guided_onboarding.devdocs.json'; diff --git a/api_docs/home.mdx b/api_docs/home.mdx index d3d512c1910550..3a4f94d92a41ef 100644 --- a/api_docs/home.mdx +++ b/api_docs/home.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/home title: "home" image: https://source.unsplash.com/400x175/?github description: API docs for the home plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'home'] --- import homeObj from './home.devdocs.json'; diff --git a/api_docs/image_embeddable.mdx b/api_docs/image_embeddable.mdx index 71b5dd26f4e7f9..c33ce792f0a244 100644 --- a/api_docs/image_embeddable.mdx +++ b/api_docs/image_embeddable.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/imageEmbeddable title: "imageEmbeddable" image: https://source.unsplash.com/400x175/?github description: API docs for the imageEmbeddable plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'imageEmbeddable'] --- import imageEmbeddableObj from './image_embeddable.devdocs.json'; diff --git a/api_docs/index_lifecycle_management.mdx b/api_docs/index_lifecycle_management.mdx index 549a2bb1abc9d9..e1a9e31bc02236 100644 --- a/api_docs/index_lifecycle_management.mdx +++ b/api_docs/index_lifecycle_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexLifecycleManagement title: "indexLifecycleManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexLifecycleManagement plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexLifecycleManagement'] --- import indexLifecycleManagementObj from './index_lifecycle_management.devdocs.json'; diff --git a/api_docs/index_management.mdx b/api_docs/index_management.mdx index 04c19c69ac493c..7709f8d69a6a57 100644 --- a/api_docs/index_management.mdx +++ b/api_docs/index_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/indexManagement title: "indexManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the indexManagement plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.devdocs.json b/api_docs/infra.devdocs.json index afd2f2c938d06b..3c6703fd87f83b 100644 --- a/api_docs/infra.devdocs.json +++ b/api_docs/infra.devdocs.json @@ -491,7 +491,7 @@ "label": "featureFlags", "description": [], "signature": [ - "{ customThresholdAlertsEnabled: boolean; logsUIEnabled: boolean; metricsExplorerEnabled: boolean; osqueryEnabled: boolean; inventoryThresholdAlertRuleEnabled: boolean; metricThresholdAlertRuleEnabled: boolean; logThresholdAlertRuleEnabled: boolean; }" + "{ customThresholdAlertsEnabled: boolean; logsUIEnabled: boolean; metricsExplorerEnabled: boolean; osqueryEnabled: boolean; inventoryThresholdAlertRuleEnabled: boolean; metricThresholdAlertRuleEnabled: boolean; logThresholdAlertRuleEnabled: boolean; alertsAndRulesDropdownEnabled: boolean; }" ], "path": "x-pack/plugins/infra/common/plugin_config_types.ts", "deprecated": false, diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index 45ae7630227c07..73cf66bd60fcd1 100644 --- a/api_docs/infra.mdx +++ b/api_docs/infra.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/infra title: "infra" image: https://source.unsplash.com/400x175/?github description: API docs for the infra plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'infra'] --- import infraObj from './infra.devdocs.json'; diff --git a/api_docs/inspector.mdx b/api_docs/inspector.mdx index 78057079336046..1726dcc786b2d7 100644 --- a/api_docs/inspector.mdx +++ b/api_docs/inspector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/inspector title: "inspector" image: https://source.unsplash.com/400x175/?github description: API docs for the inspector plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'inspector'] --- import inspectorObj from './inspector.devdocs.json'; diff --git a/api_docs/interactive_setup.mdx b/api_docs/interactive_setup.mdx index 34ac9aa7c94830..91a30cc9e15399 100644 --- a/api_docs/interactive_setup.mdx +++ b/api_docs/interactive_setup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/interactiveSetup title: "interactiveSetup" image: https://source.unsplash.com/400x175/?github description: API docs for the interactiveSetup plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'interactiveSetup'] --- import interactiveSetupObj from './interactive_setup.devdocs.json'; diff --git a/api_docs/kbn_ace.mdx b/api_docs/kbn_ace.mdx index 68be8d89d3bbd2..f38b424f888310 100644 --- a/api_docs/kbn_ace.mdx +++ b/api_docs/kbn_ace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ace title: "@kbn/ace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ace plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ace'] --- import kbnAceObj from './kbn_ace.devdocs.json'; diff --git a/api_docs/kbn_aiops_components.mdx b/api_docs/kbn_aiops_components.mdx index 3e451aca9fe60d..f5e6091c61cb03 100644 --- a/api_docs/kbn_aiops_components.mdx +++ b/api_docs/kbn_aiops_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-components title: "@kbn/aiops-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-components plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-components'] --- import kbnAiopsComponentsObj from './kbn_aiops_components.devdocs.json'; diff --git a/api_docs/kbn_aiops_utils.mdx b/api_docs/kbn_aiops_utils.mdx index 4d41812470b2ba..5a1178ebd47297 100644 --- a/api_docs/kbn_aiops_utils.mdx +++ b/api_docs/kbn_aiops_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-aiops-utils title: "@kbn/aiops-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/aiops-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/aiops-utils'] --- import kbnAiopsUtilsObj from './kbn_aiops_utils.devdocs.json'; diff --git a/api_docs/kbn_alerting_api_integration_helpers.mdx b/api_docs/kbn_alerting_api_integration_helpers.mdx index f4fe31a69e858b..585c93ea76de5a 100644 --- a/api_docs/kbn_alerting_api_integration_helpers.mdx +++ b/api_docs/kbn_alerting_api_integration_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-api-integration-helpers title: "@kbn/alerting-api-integration-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-api-integration-helpers plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-api-integration-helpers'] --- import kbnAlertingApiIntegrationHelpersObj from './kbn_alerting_api_integration_helpers.devdocs.json'; diff --git a/api_docs/kbn_alerting_state_types.mdx b/api_docs/kbn_alerting_state_types.mdx index a5635ad4f7ebe1..8e9e51356e90ff 100644 --- a/api_docs/kbn_alerting_state_types.mdx +++ b/api_docs/kbn_alerting_state_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerting-state-types title: "@kbn/alerting-state-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerting-state-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerting-state-types'] --- import kbnAlertingStateTypesObj from './kbn_alerting_state_types.devdocs.json'; diff --git a/api_docs/kbn_alerts_as_data_utils.mdx b/api_docs/kbn_alerts_as_data_utils.mdx index dfea79b586eace..c13e2e5c21089b 100644 --- a/api_docs/kbn_alerts_as_data_utils.mdx +++ b/api_docs/kbn_alerts_as_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-as-data-utils title: "@kbn/alerts-as-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-as-data-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-as-data-utils'] --- import kbnAlertsAsDataUtilsObj from './kbn_alerts_as_data_utils.devdocs.json'; diff --git a/api_docs/kbn_alerts_ui_shared.mdx b/api_docs/kbn_alerts_ui_shared.mdx index b1798274edb2f5..3c7035857d09ad 100644 --- a/api_docs/kbn_alerts_ui_shared.mdx +++ b/api_docs/kbn_alerts_ui_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-alerts-ui-shared title: "@kbn/alerts-ui-shared" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/alerts-ui-shared plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/alerts-ui-shared'] --- import kbnAlertsUiSharedObj from './kbn_alerts_ui_shared.devdocs.json'; diff --git a/api_docs/kbn_analytics.mdx b/api_docs/kbn_analytics.mdx index 5721f18d873fb9..a82286dd32079b 100644 --- a/api_docs/kbn_analytics.mdx +++ b/api_docs/kbn_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics title: "@kbn/analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics'] --- import kbnAnalyticsObj from './kbn_analytics.devdocs.json'; diff --git a/api_docs/kbn_analytics_client.mdx b/api_docs/kbn_analytics_client.mdx index 436e3da1a09965..046a74f6a917eb 100644 --- a/api_docs/kbn_analytics_client.mdx +++ b/api_docs/kbn_analytics_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-client title: "@kbn/analytics-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-client plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-client'] --- import kbnAnalyticsClientObj from './kbn_analytics_client.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx index 32feded82e4be7..115d802bf1eeef 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-browser title: "@kbn/analytics-shippers-elastic-v3-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-browser'] --- import kbnAnalyticsShippersElasticV3BrowserObj from './kbn_analytics_shippers_elastic_v3_browser.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx index 055e84b076feab..87f3b783d5a83f 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-common title: "@kbn/analytics-shippers-elastic-v3-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-common'] --- import kbnAnalyticsShippersElasticV3CommonObj from './kbn_analytics_shippers_elastic_v3_common.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx index c53f0cba8b34fd..556f660d7153bd 100644 --- a/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx +++ b/api_docs/kbn_analytics_shippers_elastic_v3_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-elastic-v3-server title: "@kbn/analytics-shippers-elastic-v3-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-elastic-v3-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-elastic-v3-server'] --- import kbnAnalyticsShippersElasticV3ServerObj from './kbn_analytics_shippers_elastic_v3_server.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_fullstory.mdx b/api_docs/kbn_analytics_shippers_fullstory.mdx index 4e4e53adcee8a8..6b58bc6ab4efa4 100644 --- a/api_docs/kbn_analytics_shippers_fullstory.mdx +++ b/api_docs/kbn_analytics_shippers_fullstory.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-fullstory title: "@kbn/analytics-shippers-fullstory" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-fullstory plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-fullstory'] --- import kbnAnalyticsShippersFullstoryObj from './kbn_analytics_shippers_fullstory.devdocs.json'; diff --git a/api_docs/kbn_analytics_shippers_gainsight.mdx b/api_docs/kbn_analytics_shippers_gainsight.mdx index 0b7113070fcedb..8439486a3fc4c5 100644 --- a/api_docs/kbn_analytics_shippers_gainsight.mdx +++ b/api_docs/kbn_analytics_shippers_gainsight.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-analytics-shippers-gainsight title: "@kbn/analytics-shippers-gainsight" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/analytics-shippers-gainsight plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/analytics-shippers-gainsight'] --- import kbnAnalyticsShippersGainsightObj from './kbn_analytics_shippers_gainsight.devdocs.json'; diff --git a/api_docs/kbn_apm_config_loader.mdx b/api_docs/kbn_apm_config_loader.mdx index 88087829525149..cf456e7a1801d7 100644 --- a/api_docs/kbn_apm_config_loader.mdx +++ b/api_docs/kbn_apm_config_loader.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-config-loader title: "@kbn/apm-config-loader" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-config-loader plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-config-loader'] --- import kbnApmConfigLoaderObj from './kbn_apm_config_loader.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace.mdx b/api_docs/kbn_apm_synthtrace.mdx index b5909a25602d5f..6a3ccf8a8496b5 100644 --- a/api_docs/kbn_apm_synthtrace.mdx +++ b/api_docs/kbn_apm_synthtrace.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace title: "@kbn/apm-synthtrace" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace'] --- import kbnApmSynthtraceObj from './kbn_apm_synthtrace.devdocs.json'; diff --git a/api_docs/kbn_apm_synthtrace_client.mdx b/api_docs/kbn_apm_synthtrace_client.mdx index 50850ee66f6f87..99e51a3970c4d3 100644 --- a/api_docs/kbn_apm_synthtrace_client.mdx +++ b/api_docs/kbn_apm_synthtrace_client.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-synthtrace-client title: "@kbn/apm-synthtrace-client" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-synthtrace-client plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-synthtrace-client'] --- import kbnApmSynthtraceClientObj from './kbn_apm_synthtrace_client.devdocs.json'; diff --git a/api_docs/kbn_apm_utils.mdx b/api_docs/kbn_apm_utils.mdx index 8229bc923376d8..a090396a46c665 100644 --- a/api_docs/kbn_apm_utils.mdx +++ b/api_docs/kbn_apm_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-apm-utils title: "@kbn/apm-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/apm-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/apm-utils'] --- import kbnApmUtilsObj from './kbn_apm_utils.devdocs.json'; diff --git a/api_docs/kbn_axe_config.mdx b/api_docs/kbn_axe_config.mdx index 4ba8b24bc4f07b..3801596178a9f2 100644 --- a/api_docs/kbn_axe_config.mdx +++ b/api_docs/kbn_axe_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-axe-config title: "@kbn/axe-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/axe-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/axe-config'] --- import kbnAxeConfigObj from './kbn_axe_config.devdocs.json'; diff --git a/api_docs/kbn_cases_components.mdx b/api_docs/kbn_cases_components.mdx index 6d08383bb63789..83f4022df056cf 100644 --- a/api_docs/kbn_cases_components.mdx +++ b/api_docs/kbn_cases_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cases-components title: "@kbn/cases-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cases-components plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cases-components'] --- import kbnCasesComponentsObj from './kbn_cases_components.devdocs.json'; diff --git a/api_docs/kbn_cell_actions.mdx b/api_docs/kbn_cell_actions.mdx index 4ce578ad0fcc5d..8ff66097b0a8e0 100644 --- a/api_docs/kbn_cell_actions.mdx +++ b/api_docs/kbn_cell_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cell-actions title: "@kbn/cell-actions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cell-actions plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cell-actions'] --- import kbnCellActionsObj from './kbn_cell_actions.devdocs.json'; diff --git a/api_docs/kbn_chart_expressions_common.mdx b/api_docs/kbn_chart_expressions_common.mdx index 930214ac6b5868..36783f5a3f9e14 100644 --- a/api_docs/kbn_chart_expressions_common.mdx +++ b/api_docs/kbn_chart_expressions_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-expressions-common title: "@kbn/chart-expressions-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-expressions-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-expressions-common'] --- import kbnChartExpressionsCommonObj from './kbn_chart_expressions_common.devdocs.json'; diff --git a/api_docs/kbn_chart_icons.mdx b/api_docs/kbn_chart_icons.mdx index 00fb479275e52f..f882409468cf0b 100644 --- a/api_docs/kbn_chart_icons.mdx +++ b/api_docs/kbn_chart_icons.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-chart-icons title: "@kbn/chart-icons" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/chart-icons plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/chart-icons'] --- import kbnChartIconsObj from './kbn_chart_icons.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_core.mdx b/api_docs/kbn_ci_stats_core.mdx index 861e78744c997e..5d45cb03ce6a6e 100644 --- a/api_docs/kbn_ci_stats_core.mdx +++ b/api_docs/kbn_ci_stats_core.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-core title: "@kbn/ci-stats-core" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-core plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-core'] --- import kbnCiStatsCoreObj from './kbn_ci_stats_core.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_performance_metrics.mdx b/api_docs/kbn_ci_stats_performance_metrics.mdx index 2a98e03410c84e..dec2354dc2bba2 100644 --- a/api_docs/kbn_ci_stats_performance_metrics.mdx +++ b/api_docs/kbn_ci_stats_performance_metrics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-performance-metrics title: "@kbn/ci-stats-performance-metrics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-performance-metrics plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-performance-metrics'] --- import kbnCiStatsPerformanceMetricsObj from './kbn_ci_stats_performance_metrics.devdocs.json'; diff --git a/api_docs/kbn_ci_stats_reporter.mdx b/api_docs/kbn_ci_stats_reporter.mdx index 5c7bc5c6487eda..0a214b7ead50f9 100644 --- a/api_docs/kbn_ci_stats_reporter.mdx +++ b/api_docs/kbn_ci_stats_reporter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ci-stats-reporter title: "@kbn/ci-stats-reporter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ci-stats-reporter plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ci-stats-reporter'] --- import kbnCiStatsReporterObj from './kbn_ci_stats_reporter.devdocs.json'; diff --git a/api_docs/kbn_cli_dev_mode.mdx b/api_docs/kbn_cli_dev_mode.mdx index aea521f3fae33b..41e4a073812ee6 100644 --- a/api_docs/kbn_cli_dev_mode.mdx +++ b/api_docs/kbn_cli_dev_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cli-dev-mode title: "@kbn/cli-dev-mode" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cli-dev-mode plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cli-dev-mode'] --- import kbnCliDevModeObj from './kbn_cli_dev_mode.devdocs.json'; diff --git a/api_docs/kbn_code_editor.mdx b/api_docs/kbn_code_editor.mdx index 1dc2eaf4b16adc..28dc39ff1c6ea1 100644 --- a/api_docs/kbn_code_editor.mdx +++ b/api_docs/kbn_code_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor title: "@kbn/code-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor'] --- import kbnCodeEditorObj from './kbn_code_editor.devdocs.json'; diff --git a/api_docs/kbn_code_editor_mocks.mdx b/api_docs/kbn_code_editor_mocks.mdx index 81e88c19befb66..339212befce665 100644 --- a/api_docs/kbn_code_editor_mocks.mdx +++ b/api_docs/kbn_code_editor_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-code-editor-mocks title: "@kbn/code-editor-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/code-editor-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/code-editor-mocks'] --- import kbnCodeEditorMocksObj from './kbn_code_editor_mocks.devdocs.json'; diff --git a/api_docs/kbn_coloring.mdx b/api_docs/kbn_coloring.mdx index 5ddf16675e41c3..fea485791c2a45 100644 --- a/api_docs/kbn_coloring.mdx +++ b/api_docs/kbn_coloring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-coloring title: "@kbn/coloring" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/coloring plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/coloring'] --- import kbnColoringObj from './kbn_coloring.devdocs.json'; diff --git a/api_docs/kbn_config.mdx b/api_docs/kbn_config.mdx index 2a81c7066ffb48..0c9c4af35cd57e 100644 --- a/api_docs/kbn_config.mdx +++ b/api_docs/kbn_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config title: "@kbn/config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config'] --- import kbnConfigObj from './kbn_config.devdocs.json'; diff --git a/api_docs/kbn_config_mocks.mdx b/api_docs/kbn_config_mocks.mdx index b18cc89349d519..cb98963d926ab4 100644 --- a/api_docs/kbn_config_mocks.mdx +++ b/api_docs/kbn_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-mocks title: "@kbn/config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-mocks'] --- import kbnConfigMocksObj from './kbn_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_config_schema.mdx b/api_docs/kbn_config_schema.mdx index 49f78c5cb750c5..c877a900607053 100644 --- a/api_docs/kbn_config_schema.mdx +++ b/api_docs/kbn_config_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-config-schema title: "@kbn/config-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/config-schema plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/config-schema'] --- import kbnConfigSchemaObj from './kbn_config_schema.devdocs.json'; diff --git a/api_docs/kbn_content_management_content_editor.mdx b/api_docs/kbn_content_management_content_editor.mdx index 9c5685b4bc9251..b962a511cd5fd3 100644 --- a/api_docs/kbn_content_management_content_editor.mdx +++ b/api_docs/kbn_content_management_content_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-content-editor title: "@kbn/content-management-content-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-content-editor plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-content-editor'] --- import kbnContentManagementContentEditorObj from './kbn_content_management_content_editor.devdocs.json'; diff --git a/api_docs/kbn_content_management_tabbed_table_list_view.mdx b/api_docs/kbn_content_management_tabbed_table_list_view.mdx index ec0208b509947d..f6511b8f147f8d 100644 --- a/api_docs/kbn_content_management_tabbed_table_list_view.mdx +++ b/api_docs/kbn_content_management_tabbed_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-tabbed-table-list-view title: "@kbn/content-management-tabbed-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-tabbed-table-list-view plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-tabbed-table-list-view'] --- import kbnContentManagementTabbedTableListViewObj from './kbn_content_management_tabbed_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view.mdx b/api_docs/kbn_content_management_table_list_view.mdx index 1fca264dea91ed..eccac459cdc80f 100644 --- a/api_docs/kbn_content_management_table_list_view.mdx +++ b/api_docs/kbn_content_management_table_list_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view title: "@kbn/content-management-table-list-view" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view'] --- import kbnContentManagementTableListViewObj from './kbn_content_management_table_list_view.devdocs.json'; diff --git a/api_docs/kbn_content_management_table_list_view_table.mdx b/api_docs/kbn_content_management_table_list_view_table.mdx index b0d141620b948e..70c8d29c339525 100644 --- a/api_docs/kbn_content_management_table_list_view_table.mdx +++ b/api_docs/kbn_content_management_table_list_view_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-table-list-view-table title: "@kbn/content-management-table-list-view-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-table-list-view-table plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-table-list-view-table'] --- import kbnContentManagementTableListViewTableObj from './kbn_content_management_table_list_view_table.devdocs.json'; diff --git a/api_docs/kbn_content_management_utils.mdx b/api_docs/kbn_content_management_utils.mdx index d3c3c0c809864d..407ee537b77136 100644 --- a/api_docs/kbn_content_management_utils.mdx +++ b/api_docs/kbn_content_management_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-content-management-utils title: "@kbn/content-management-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/content-management-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/content-management-utils'] --- import kbnContentManagementUtilsObj from './kbn_content_management_utils.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser.mdx b/api_docs/kbn_core_analytics_browser.mdx index 7d53b2dc16277c..83a686e3750cd9 100644 --- a/api_docs/kbn_core_analytics_browser.mdx +++ b/api_docs/kbn_core_analytics_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser title: "@kbn/core-analytics-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser'] --- import kbnCoreAnalyticsBrowserObj from './kbn_core_analytics_browser.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_internal.mdx b/api_docs/kbn_core_analytics_browser_internal.mdx index 3c217db828bca7..639022010cc7f3 100644 --- a/api_docs/kbn_core_analytics_browser_internal.mdx +++ b/api_docs/kbn_core_analytics_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-internal title: "@kbn/core-analytics-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-internal'] --- import kbnCoreAnalyticsBrowserInternalObj from './kbn_core_analytics_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_browser_mocks.mdx b/api_docs/kbn_core_analytics_browser_mocks.mdx index 1c44dc388afbce..d79dc1908333c7 100644 --- a/api_docs/kbn_core_analytics_browser_mocks.mdx +++ b/api_docs/kbn_core_analytics_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-browser-mocks title: "@kbn/core-analytics-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-browser-mocks'] --- import kbnCoreAnalyticsBrowserMocksObj from './kbn_core_analytics_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server.mdx b/api_docs/kbn_core_analytics_server.mdx index 0f1d1db3078933..10d76a7b0ef42f 100644 --- a/api_docs/kbn_core_analytics_server.mdx +++ b/api_docs/kbn_core_analytics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server title: "@kbn/core-analytics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server'] --- import kbnCoreAnalyticsServerObj from './kbn_core_analytics_server.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_internal.mdx b/api_docs/kbn_core_analytics_server_internal.mdx index ca03e04609ed76..568825ebcaceda 100644 --- a/api_docs/kbn_core_analytics_server_internal.mdx +++ b/api_docs/kbn_core_analytics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-internal title: "@kbn/core-analytics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-internal'] --- import kbnCoreAnalyticsServerInternalObj from './kbn_core_analytics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_analytics_server_mocks.mdx b/api_docs/kbn_core_analytics_server_mocks.mdx index 785fd0a831ce07..bef690af1e88c6 100644 --- a/api_docs/kbn_core_analytics_server_mocks.mdx +++ b/api_docs/kbn_core_analytics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-analytics-server-mocks title: "@kbn/core-analytics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-analytics-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-analytics-server-mocks'] --- import kbnCoreAnalyticsServerMocksObj from './kbn_core_analytics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser.mdx b/api_docs/kbn_core_application_browser.mdx index 9d20a0ce8ff9e1..076e341e586209 100644 --- a/api_docs/kbn_core_application_browser.mdx +++ b/api_docs/kbn_core_application_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser title: "@kbn/core-application-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser'] --- import kbnCoreApplicationBrowserObj from './kbn_core_application_browser.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_internal.mdx b/api_docs/kbn_core_application_browser_internal.mdx index 557165a2a664c5..6edaaa2cf33283 100644 --- a/api_docs/kbn_core_application_browser_internal.mdx +++ b/api_docs/kbn_core_application_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-internal title: "@kbn/core-application-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-internal'] --- import kbnCoreApplicationBrowserInternalObj from './kbn_core_application_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_application_browser_mocks.mdx b/api_docs/kbn_core_application_browser_mocks.mdx index d19a5a75ff1e99..4e8c4cb7d717ff 100644 --- a/api_docs/kbn_core_application_browser_mocks.mdx +++ b/api_docs/kbn_core_application_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-browser-mocks title: "@kbn/core-application-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-browser-mocks'] --- import kbnCoreApplicationBrowserMocksObj from './kbn_core_application_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_application_common.mdx b/api_docs/kbn_core_application_common.mdx index a9c68f78b67962..043b7012a94e34 100644 --- a/api_docs/kbn_core_application_common.mdx +++ b/api_docs/kbn_core_application_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-application-common title: "@kbn/core-application-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-application-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-application-common'] --- import kbnCoreApplicationCommonObj from './kbn_core_application_common.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_internal.mdx b/api_docs/kbn_core_apps_browser_internal.mdx index a249fc254c4c1e..6994e3b0edf094 100644 --- a/api_docs/kbn_core_apps_browser_internal.mdx +++ b/api_docs/kbn_core_apps_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-internal title: "@kbn/core-apps-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-internal'] --- import kbnCoreAppsBrowserInternalObj from './kbn_core_apps_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_apps_browser_mocks.mdx b/api_docs/kbn_core_apps_browser_mocks.mdx index b4279a8c3dcba7..7cb8a76a171810 100644 --- a/api_docs/kbn_core_apps_browser_mocks.mdx +++ b/api_docs/kbn_core_apps_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-browser-mocks title: "@kbn/core-apps-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-browser-mocks'] --- import kbnCoreAppsBrowserMocksObj from './kbn_core_apps_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_apps_server_internal.mdx b/api_docs/kbn_core_apps_server_internal.mdx index f2c5c265fd02f9..a8d97a1a810dc3 100644 --- a/api_docs/kbn_core_apps_server_internal.mdx +++ b/api_docs/kbn_core_apps_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-apps-server-internal title: "@kbn/core-apps-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-apps-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-apps-server-internal'] --- import kbnCoreAppsServerInternalObj from './kbn_core_apps_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_browser_mocks.mdx b/api_docs/kbn_core_base_browser_mocks.mdx index 5bfb16dbca6003..e6f793f9f07806 100644 --- a/api_docs/kbn_core_base_browser_mocks.mdx +++ b/api_docs/kbn_core_base_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-browser-mocks title: "@kbn/core-base-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-browser-mocks'] --- import kbnCoreBaseBrowserMocksObj from './kbn_core_base_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_base_common.mdx b/api_docs/kbn_core_base_common.mdx index 09a8b74d1970b1..5ebb3496aca14e 100644 --- a/api_docs/kbn_core_base_common.mdx +++ b/api_docs/kbn_core_base_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-common title: "@kbn/core-base-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-common'] --- import kbnCoreBaseCommonObj from './kbn_core_base_common.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_internal.mdx b/api_docs/kbn_core_base_server_internal.mdx index 4e5f6a1acf382c..88c6c91c9fe8af 100644 --- a/api_docs/kbn_core_base_server_internal.mdx +++ b/api_docs/kbn_core_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-internal title: "@kbn/core-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-internal'] --- import kbnCoreBaseServerInternalObj from './kbn_core_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_base_server_mocks.mdx b/api_docs/kbn_core_base_server_mocks.mdx index 82197bb1f5c729..024fcf220b143b 100644 --- a/api_docs/kbn_core_base_server_mocks.mdx +++ b/api_docs/kbn_core_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-base-server-mocks title: "@kbn/core-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-base-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-base-server-mocks'] --- import kbnCoreBaseServerMocksObj from './kbn_core_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_browser_mocks.mdx b/api_docs/kbn_core_capabilities_browser_mocks.mdx index 913730b81e43de..eaa9a542e93808 100644 --- a/api_docs/kbn_core_capabilities_browser_mocks.mdx +++ b/api_docs/kbn_core_capabilities_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-browser-mocks title: "@kbn/core-capabilities-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-browser-mocks'] --- import kbnCoreCapabilitiesBrowserMocksObj from './kbn_core_capabilities_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_common.mdx b/api_docs/kbn_core_capabilities_common.mdx index 0358f8f75e331b..8044f2298941c8 100644 --- a/api_docs/kbn_core_capabilities_common.mdx +++ b/api_docs/kbn_core_capabilities_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-common title: "@kbn/core-capabilities-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-common'] --- import kbnCoreCapabilitiesCommonObj from './kbn_core_capabilities_common.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server.mdx b/api_docs/kbn_core_capabilities_server.mdx index 3a2c69d06f83da..f657de9a12774a 100644 --- a/api_docs/kbn_core_capabilities_server.mdx +++ b/api_docs/kbn_core_capabilities_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server title: "@kbn/core-capabilities-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server'] --- import kbnCoreCapabilitiesServerObj from './kbn_core_capabilities_server.devdocs.json'; diff --git a/api_docs/kbn_core_capabilities_server_mocks.mdx b/api_docs/kbn_core_capabilities_server_mocks.mdx index 7b1b8ed0eacc77..af77f63119f674 100644 --- a/api_docs/kbn_core_capabilities_server_mocks.mdx +++ b/api_docs/kbn_core_capabilities_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-capabilities-server-mocks title: "@kbn/core-capabilities-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-capabilities-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-capabilities-server-mocks'] --- import kbnCoreCapabilitiesServerMocksObj from './kbn_core_capabilities_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser.mdx b/api_docs/kbn_core_chrome_browser.mdx index f2c2638f5fa0f2..2a7abe946bead4 100644 --- a/api_docs/kbn_core_chrome_browser.mdx +++ b/api_docs/kbn_core_chrome_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser title: "@kbn/core-chrome-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser'] --- import kbnCoreChromeBrowserObj from './kbn_core_chrome_browser.devdocs.json'; diff --git a/api_docs/kbn_core_chrome_browser_mocks.mdx b/api_docs/kbn_core_chrome_browser_mocks.mdx index dbe07b0c5f684f..08b307f79c5577 100644 --- a/api_docs/kbn_core_chrome_browser_mocks.mdx +++ b/api_docs/kbn_core_chrome_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-chrome-browser-mocks title: "@kbn/core-chrome-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-chrome-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-chrome-browser-mocks'] --- import kbnCoreChromeBrowserMocksObj from './kbn_core_chrome_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_config_server_internal.mdx b/api_docs/kbn_core_config_server_internal.mdx index 216074f7dc8eba..438a73bcce5f49 100644 --- a/api_docs/kbn_core_config_server_internal.mdx +++ b/api_docs/kbn_core_config_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-config-server-internal title: "@kbn/core-config-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-config-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-config-server-internal'] --- import kbnCoreConfigServerInternalObj from './kbn_core_config_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser.mdx b/api_docs/kbn_core_custom_branding_browser.mdx index 3884deb3937e80..f96b1321fa7c05 100644 --- a/api_docs/kbn_core_custom_branding_browser.mdx +++ b/api_docs/kbn_core_custom_branding_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser title: "@kbn/core-custom-branding-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser'] --- import kbnCoreCustomBrandingBrowserObj from './kbn_core_custom_branding_browser.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_internal.mdx b/api_docs/kbn_core_custom_branding_browser_internal.mdx index 53da1c99e9b8cc..5b09909d4e6ab3 100644 --- a/api_docs/kbn_core_custom_branding_browser_internal.mdx +++ b/api_docs/kbn_core_custom_branding_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-internal title: "@kbn/core-custom-branding-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-internal'] --- import kbnCoreCustomBrandingBrowserInternalObj from './kbn_core_custom_branding_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_browser_mocks.mdx b/api_docs/kbn_core_custom_branding_browser_mocks.mdx index 9a2322738ecc47..e460cc07ac2f3f 100644 --- a/api_docs/kbn_core_custom_branding_browser_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-browser-mocks title: "@kbn/core-custom-branding-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-browser-mocks'] --- import kbnCoreCustomBrandingBrowserMocksObj from './kbn_core_custom_branding_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_common.mdx b/api_docs/kbn_core_custom_branding_common.mdx index d477fdf12e5b8e..df6f2a5266059e 100644 --- a/api_docs/kbn_core_custom_branding_common.mdx +++ b/api_docs/kbn_core_custom_branding_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-common title: "@kbn/core-custom-branding-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-common'] --- import kbnCoreCustomBrandingCommonObj from './kbn_core_custom_branding_common.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server.mdx b/api_docs/kbn_core_custom_branding_server.mdx index 5c498103cef6dd..8f8c9363081b63 100644 --- a/api_docs/kbn_core_custom_branding_server.mdx +++ b/api_docs/kbn_core_custom_branding_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server title: "@kbn/core-custom-branding-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server'] --- import kbnCoreCustomBrandingServerObj from './kbn_core_custom_branding_server.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_internal.mdx b/api_docs/kbn_core_custom_branding_server_internal.mdx index a389eef35d8a5c..494ba8c722b208 100644 --- a/api_docs/kbn_core_custom_branding_server_internal.mdx +++ b/api_docs/kbn_core_custom_branding_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-internal title: "@kbn/core-custom-branding-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-internal'] --- import kbnCoreCustomBrandingServerInternalObj from './kbn_core_custom_branding_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_custom_branding_server_mocks.mdx b/api_docs/kbn_core_custom_branding_server_mocks.mdx index 28a5f77439dabc..815487b66e640e 100644 --- a/api_docs/kbn_core_custom_branding_server_mocks.mdx +++ b/api_docs/kbn_core_custom_branding_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-custom-branding-server-mocks title: "@kbn/core-custom-branding-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-custom-branding-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-custom-branding-server-mocks'] --- import kbnCoreCustomBrandingServerMocksObj from './kbn_core_custom_branding_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser.mdx b/api_docs/kbn_core_deprecations_browser.mdx index d5585e494ab28d..a58494792000ba 100644 --- a/api_docs/kbn_core_deprecations_browser.mdx +++ b/api_docs/kbn_core_deprecations_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser title: "@kbn/core-deprecations-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser'] --- import kbnCoreDeprecationsBrowserObj from './kbn_core_deprecations_browser.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_internal.mdx b/api_docs/kbn_core_deprecations_browser_internal.mdx index 866b83eada4adf..06a9d5a391ef4b 100644 --- a/api_docs/kbn_core_deprecations_browser_internal.mdx +++ b/api_docs/kbn_core_deprecations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-internal title: "@kbn/core-deprecations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-internal'] --- import kbnCoreDeprecationsBrowserInternalObj from './kbn_core_deprecations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_browser_mocks.mdx b/api_docs/kbn_core_deprecations_browser_mocks.mdx index fcb55fc79dde33..a2794f801b3e10 100644 --- a/api_docs/kbn_core_deprecations_browser_mocks.mdx +++ b/api_docs/kbn_core_deprecations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-browser-mocks title: "@kbn/core-deprecations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-browser-mocks'] --- import kbnCoreDeprecationsBrowserMocksObj from './kbn_core_deprecations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_common.mdx b/api_docs/kbn_core_deprecations_common.mdx index 63f4e42428a65f..e359d6da8a044d 100644 --- a/api_docs/kbn_core_deprecations_common.mdx +++ b/api_docs/kbn_core_deprecations_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-common title: "@kbn/core-deprecations-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-common'] --- import kbnCoreDeprecationsCommonObj from './kbn_core_deprecations_common.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server.mdx b/api_docs/kbn_core_deprecations_server.mdx index c4aecd17f9f660..504c8ba87f0cb5 100644 --- a/api_docs/kbn_core_deprecations_server.mdx +++ b/api_docs/kbn_core_deprecations_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server title: "@kbn/core-deprecations-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server'] --- import kbnCoreDeprecationsServerObj from './kbn_core_deprecations_server.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_internal.mdx b/api_docs/kbn_core_deprecations_server_internal.mdx index 490b541ebaecfc..dc513584c94fc4 100644 --- a/api_docs/kbn_core_deprecations_server_internal.mdx +++ b/api_docs/kbn_core_deprecations_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-internal title: "@kbn/core-deprecations-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-internal'] --- import kbnCoreDeprecationsServerInternalObj from './kbn_core_deprecations_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_deprecations_server_mocks.mdx b/api_docs/kbn_core_deprecations_server_mocks.mdx index 1ab07100a17c69..5c98c30ea723fa 100644 --- a/api_docs/kbn_core_deprecations_server_mocks.mdx +++ b/api_docs/kbn_core_deprecations_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-deprecations-server-mocks title: "@kbn/core-deprecations-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-deprecations-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-deprecations-server-mocks'] --- import kbnCoreDeprecationsServerMocksObj from './kbn_core_deprecations_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser.mdx b/api_docs/kbn_core_doc_links_browser.mdx index aaeaa37fa2ad31..bc17f94aa6260f 100644 --- a/api_docs/kbn_core_doc_links_browser.mdx +++ b/api_docs/kbn_core_doc_links_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser title: "@kbn/core-doc-links-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser'] --- import kbnCoreDocLinksBrowserObj from './kbn_core_doc_links_browser.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_browser_mocks.mdx b/api_docs/kbn_core_doc_links_browser_mocks.mdx index 64317f32f1d7b6..c06b8cc8e8732b 100644 --- a/api_docs/kbn_core_doc_links_browser_mocks.mdx +++ b/api_docs/kbn_core_doc_links_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-browser-mocks title: "@kbn/core-doc-links-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-browser-mocks'] --- import kbnCoreDocLinksBrowserMocksObj from './kbn_core_doc_links_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server.mdx b/api_docs/kbn_core_doc_links_server.mdx index 2f3a11bab23f51..87be111a516010 100644 --- a/api_docs/kbn_core_doc_links_server.mdx +++ b/api_docs/kbn_core_doc_links_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server title: "@kbn/core-doc-links-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server'] --- import kbnCoreDocLinksServerObj from './kbn_core_doc_links_server.devdocs.json'; diff --git a/api_docs/kbn_core_doc_links_server_mocks.mdx b/api_docs/kbn_core_doc_links_server_mocks.mdx index 054dbb2f4b4cf9..4be110e4e8700b 100644 --- a/api_docs/kbn_core_doc_links_server_mocks.mdx +++ b/api_docs/kbn_core_doc_links_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-doc-links-server-mocks title: "@kbn/core-doc-links-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-doc-links-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-doc-links-server-mocks'] --- import kbnCoreDocLinksServerMocksObj from './kbn_core_doc_links_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx index 4ee84004487445..5159fd50a5d7ce 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-internal title: "@kbn/core-elasticsearch-client-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-internal'] --- import kbnCoreElasticsearchClientServerInternalObj from './kbn_core_elasticsearch_client_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx index f3892212f7efae..78227aab4e6e68 100644 --- a/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_client_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-client-server-mocks title: "@kbn/core-elasticsearch-client-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-client-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-client-server-mocks'] --- import kbnCoreElasticsearchClientServerMocksObj from './kbn_core_elasticsearch_client_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server.mdx b/api_docs/kbn_core_elasticsearch_server.mdx index 7fc9fb000d2d65..21d511843b0706 100644 --- a/api_docs/kbn_core_elasticsearch_server.mdx +++ b/api_docs/kbn_core_elasticsearch_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server title: "@kbn/core-elasticsearch-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server'] --- import kbnCoreElasticsearchServerObj from './kbn_core_elasticsearch_server.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_internal.mdx b/api_docs/kbn_core_elasticsearch_server_internal.mdx index 398ef620bd3078..87fb4ccc9aca2b 100644 --- a/api_docs/kbn_core_elasticsearch_server_internal.mdx +++ b/api_docs/kbn_core_elasticsearch_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-internal title: "@kbn/core-elasticsearch-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-internal'] --- import kbnCoreElasticsearchServerInternalObj from './kbn_core_elasticsearch_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_elasticsearch_server_mocks.mdx b/api_docs/kbn_core_elasticsearch_server_mocks.mdx index 30c0bf3bb0d980..9c340954671887 100644 --- a/api_docs/kbn_core_elasticsearch_server_mocks.mdx +++ b/api_docs/kbn_core_elasticsearch_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-elasticsearch-server-mocks title: "@kbn/core-elasticsearch-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-elasticsearch-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-elasticsearch-server-mocks'] --- import kbnCoreElasticsearchServerMocksObj from './kbn_core_elasticsearch_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_internal.mdx b/api_docs/kbn_core_environment_server_internal.mdx index ca77ccbf229877..e7e64200288aa8 100644 --- a/api_docs/kbn_core_environment_server_internal.mdx +++ b/api_docs/kbn_core_environment_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-internal title: "@kbn/core-environment-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-internal'] --- import kbnCoreEnvironmentServerInternalObj from './kbn_core_environment_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_environment_server_mocks.mdx b/api_docs/kbn_core_environment_server_mocks.mdx index a802fb353f2b37..b86db5707798c8 100644 --- a/api_docs/kbn_core_environment_server_mocks.mdx +++ b/api_docs/kbn_core_environment_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-environment-server-mocks title: "@kbn/core-environment-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-environment-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-environment-server-mocks'] --- import kbnCoreEnvironmentServerMocksObj from './kbn_core_environment_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser.mdx b/api_docs/kbn_core_execution_context_browser.mdx index 74c3c19eb98a91..e730984c794dfa 100644 --- a/api_docs/kbn_core_execution_context_browser.mdx +++ b/api_docs/kbn_core_execution_context_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser title: "@kbn/core-execution-context-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser'] --- import kbnCoreExecutionContextBrowserObj from './kbn_core_execution_context_browser.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_internal.mdx b/api_docs/kbn_core_execution_context_browser_internal.mdx index e47be0b47206c1..ebeb2a2543e504 100644 --- a/api_docs/kbn_core_execution_context_browser_internal.mdx +++ b/api_docs/kbn_core_execution_context_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-internal title: "@kbn/core-execution-context-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-internal'] --- import kbnCoreExecutionContextBrowserInternalObj from './kbn_core_execution_context_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_browser_mocks.mdx b/api_docs/kbn_core_execution_context_browser_mocks.mdx index 3f0f38cb8f11b0..eab602dfbd149e 100644 --- a/api_docs/kbn_core_execution_context_browser_mocks.mdx +++ b/api_docs/kbn_core_execution_context_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-browser-mocks title: "@kbn/core-execution-context-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-browser-mocks'] --- import kbnCoreExecutionContextBrowserMocksObj from './kbn_core_execution_context_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_common.mdx b/api_docs/kbn_core_execution_context_common.mdx index 400457c51ad5c1..669ce162baf450 100644 --- a/api_docs/kbn_core_execution_context_common.mdx +++ b/api_docs/kbn_core_execution_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-common title: "@kbn/core-execution-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-common'] --- import kbnCoreExecutionContextCommonObj from './kbn_core_execution_context_common.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server.mdx b/api_docs/kbn_core_execution_context_server.mdx index 3b17dc891703b6..b619709cd6e7e8 100644 --- a/api_docs/kbn_core_execution_context_server.mdx +++ b/api_docs/kbn_core_execution_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server title: "@kbn/core-execution-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server'] --- import kbnCoreExecutionContextServerObj from './kbn_core_execution_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_internal.mdx b/api_docs/kbn_core_execution_context_server_internal.mdx index f736782948d31c..a2dcc33a3b659c 100644 --- a/api_docs/kbn_core_execution_context_server_internal.mdx +++ b/api_docs/kbn_core_execution_context_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-internal title: "@kbn/core-execution-context-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-internal'] --- import kbnCoreExecutionContextServerInternalObj from './kbn_core_execution_context_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_execution_context_server_mocks.mdx b/api_docs/kbn_core_execution_context_server_mocks.mdx index 4cfc92700bddbd..4e5c8da0d29046 100644 --- a/api_docs/kbn_core_execution_context_server_mocks.mdx +++ b/api_docs/kbn_core_execution_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-execution-context-server-mocks title: "@kbn/core-execution-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-execution-context-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-execution-context-server-mocks'] --- import kbnCoreExecutionContextServerMocksObj from './kbn_core_execution_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser.mdx b/api_docs/kbn_core_fatal_errors_browser.mdx index cfae1af034cb5d..bdb54b010b73e4 100644 --- a/api_docs/kbn_core_fatal_errors_browser.mdx +++ b/api_docs/kbn_core_fatal_errors_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser title: "@kbn/core-fatal-errors-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser'] --- import kbnCoreFatalErrorsBrowserObj from './kbn_core_fatal_errors_browser.devdocs.json'; diff --git a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx index 07f938c72e087e..2800dab944d4ad 100644 --- a/api_docs/kbn_core_fatal_errors_browser_mocks.mdx +++ b/api_docs/kbn_core_fatal_errors_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-fatal-errors-browser-mocks title: "@kbn/core-fatal-errors-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-fatal-errors-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-fatal-errors-browser-mocks'] --- import kbnCoreFatalErrorsBrowserMocksObj from './kbn_core_fatal_errors_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser.mdx b/api_docs/kbn_core_http_browser.mdx index 58881d9e8143c4..833cc3447bb4a0 100644 --- a/api_docs/kbn_core_http_browser.mdx +++ b/api_docs/kbn_core_http_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser title: "@kbn/core-http-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser'] --- import kbnCoreHttpBrowserObj from './kbn_core_http_browser.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_internal.mdx b/api_docs/kbn_core_http_browser_internal.mdx index 269097e6321d57..ea8fe3fc675592 100644 --- a/api_docs/kbn_core_http_browser_internal.mdx +++ b/api_docs/kbn_core_http_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-internal title: "@kbn/core-http-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-internal'] --- import kbnCoreHttpBrowserInternalObj from './kbn_core_http_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_browser_mocks.mdx b/api_docs/kbn_core_http_browser_mocks.mdx index 51531874456c17..86287ae2ce40d1 100644 --- a/api_docs/kbn_core_http_browser_mocks.mdx +++ b/api_docs/kbn_core_http_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-browser-mocks title: "@kbn/core-http-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-browser-mocks'] --- import kbnCoreHttpBrowserMocksObj from './kbn_core_http_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_common.mdx b/api_docs/kbn_core_http_common.mdx index 3a2e02f8eaa9c9..5c996a9aee8fae 100644 --- a/api_docs/kbn_core_http_common.mdx +++ b/api_docs/kbn_core_http_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-common title: "@kbn/core-http-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-common'] --- import kbnCoreHttpCommonObj from './kbn_core_http_common.devdocs.json'; diff --git a/api_docs/kbn_core_http_context_server_mocks.mdx b/api_docs/kbn_core_http_context_server_mocks.mdx index a3fe2dd0bd0ee3..2dd107d18bda1b 100644 --- a/api_docs/kbn_core_http_context_server_mocks.mdx +++ b/api_docs/kbn_core_http_context_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-context-server-mocks title: "@kbn/core-http-context-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-context-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-context-server-mocks'] --- import kbnCoreHttpContextServerMocksObj from './kbn_core_http_context_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_request_handler_context_server.mdx b/api_docs/kbn_core_http_request_handler_context_server.mdx index 01e9afa15ad1e2..d42f1410f953d2 100644 --- a/api_docs/kbn_core_http_request_handler_context_server.mdx +++ b/api_docs/kbn_core_http_request_handler_context_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-request-handler-context-server title: "@kbn/core-http-request-handler-context-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-request-handler-context-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-request-handler-context-server'] --- import kbnCoreHttpRequestHandlerContextServerObj from './kbn_core_http_request_handler_context_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server.mdx b/api_docs/kbn_core_http_resources_server.mdx index 87b9b53cb100bc..68095fec0c8a1f 100644 --- a/api_docs/kbn_core_http_resources_server.mdx +++ b/api_docs/kbn_core_http_resources_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server title: "@kbn/core-http-resources-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server'] --- import kbnCoreHttpResourcesServerObj from './kbn_core_http_resources_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_internal.mdx b/api_docs/kbn_core_http_resources_server_internal.mdx index 4b39c0686c81a2..aca1a2c8d33645 100644 --- a/api_docs/kbn_core_http_resources_server_internal.mdx +++ b/api_docs/kbn_core_http_resources_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-internal title: "@kbn/core-http-resources-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-internal'] --- import kbnCoreHttpResourcesServerInternalObj from './kbn_core_http_resources_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_resources_server_mocks.mdx b/api_docs/kbn_core_http_resources_server_mocks.mdx index e1587695e5837a..f42fffb4919fdf 100644 --- a/api_docs/kbn_core_http_resources_server_mocks.mdx +++ b/api_docs/kbn_core_http_resources_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-resources-server-mocks title: "@kbn/core-http-resources-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-resources-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-resources-server-mocks'] --- import kbnCoreHttpResourcesServerMocksObj from './kbn_core_http_resources_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_internal.mdx b/api_docs/kbn_core_http_router_server_internal.mdx index 81f16c1ddc5ef7..c5b9132a610d1a 100644 --- a/api_docs/kbn_core_http_router_server_internal.mdx +++ b/api_docs/kbn_core_http_router_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-internal title: "@kbn/core-http-router-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-internal'] --- import kbnCoreHttpRouterServerInternalObj from './kbn_core_http_router_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_router_server_mocks.mdx b/api_docs/kbn_core_http_router_server_mocks.mdx index 2d27389deb5280..807cb1cd57fe91 100644 --- a/api_docs/kbn_core_http_router_server_mocks.mdx +++ b/api_docs/kbn_core_http_router_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-router-server-mocks title: "@kbn/core-http-router-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-router-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-router-server-mocks'] --- import kbnCoreHttpRouterServerMocksObj from './kbn_core_http_router_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_http_server.devdocs.json b/api_docs/kbn_core_http_server.devdocs.json index acd3abd81b3c34..49b083c681418b 100644 --- a/api_docs/kbn_core_http_server.devdocs.json +++ b/api_docs/kbn_core_http_server.devdocs.json @@ -13601,6 +13601,10 @@ "plugin": "sessionView", "path": "x-pack/plugins/session_view/server/routes/get_total_io_bytes_route.ts" }, + { + "plugin": "synthetics", + "path": "x-pack/plugins/synthetics/server/server.ts" + }, { "plugin": "transform", "path": "x-pack/plugins/transform/server/routes/api/transforms_audit_messages.ts" @@ -13989,6 +13993,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/tags/routes/create_tag.ts" }, + { + "plugin": "synthetics", + "path": "x-pack/plugins/synthetics/server/server.ts" + }, { "plugin": "transform", "path": "x-pack/plugins/transform/server/routes/api/transforms.ts" @@ -14833,6 +14841,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/endpoint/routes/protection_updates_note/index.ts" }, + { + "plugin": "synthetics", + "path": "x-pack/plugins/synthetics/server/server.ts" + }, { "plugin": "transform", "path": "x-pack/plugins/transform/server/routes/api/field_histograms.ts" @@ -15269,6 +15281,10 @@ "plugin": "securitySolution", "path": "x-pack/plugins/security_solution/server/lib/risk_score/stored_scripts/delete_script_route.ts" }, + { + "plugin": "synthetics", + "path": "x-pack/plugins/synthetics/server/server.ts" + }, { "plugin": "@kbn/core-http-router-server-internal", "path": "packages/core/http/core-http-router-server-internal/src/versioned_router/core_versioned_router.ts" diff --git a/api_docs/kbn_core_http_server.mdx b/api_docs/kbn_core_http_server.mdx index 470b7d5917fbf0..79ff813ca78132 100644 --- a/api_docs/kbn_core_http_server.mdx +++ b/api_docs/kbn_core_http_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server title: "@kbn/core-http-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server'] --- import kbnCoreHttpServerObj from './kbn_core_http_server.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_internal.mdx b/api_docs/kbn_core_http_server_internal.mdx index 16ae4b8da013ea..fe5c85d5cc4605 100644 --- a/api_docs/kbn_core_http_server_internal.mdx +++ b/api_docs/kbn_core_http_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-internal title: "@kbn/core-http-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-internal'] --- import kbnCoreHttpServerInternalObj from './kbn_core_http_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_http_server_mocks.mdx b/api_docs/kbn_core_http_server_mocks.mdx index cb9d4c7cc9aaeb..d13fc1a079c982 100644 --- a/api_docs/kbn_core_http_server_mocks.mdx +++ b/api_docs/kbn_core_http_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-http-server-mocks title: "@kbn/core-http-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-http-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-http-server-mocks'] --- import kbnCoreHttpServerMocksObj from './kbn_core_http_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser.mdx b/api_docs/kbn_core_i18n_browser.mdx index cf3b0afc43afd1..d9e807d3c31f97 100644 --- a/api_docs/kbn_core_i18n_browser.mdx +++ b/api_docs/kbn_core_i18n_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser title: "@kbn/core-i18n-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser'] --- import kbnCoreI18nBrowserObj from './kbn_core_i18n_browser.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_browser_mocks.mdx b/api_docs/kbn_core_i18n_browser_mocks.mdx index 790f1e1baab51f..3f1543b464da97 100644 --- a/api_docs/kbn_core_i18n_browser_mocks.mdx +++ b/api_docs/kbn_core_i18n_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-browser-mocks title: "@kbn/core-i18n-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-browser-mocks'] --- import kbnCoreI18nBrowserMocksObj from './kbn_core_i18n_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server.mdx b/api_docs/kbn_core_i18n_server.mdx index facb131fd97bca..445399d7b2caf4 100644 --- a/api_docs/kbn_core_i18n_server.mdx +++ b/api_docs/kbn_core_i18n_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server title: "@kbn/core-i18n-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server'] --- import kbnCoreI18nServerObj from './kbn_core_i18n_server.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_internal.mdx b/api_docs/kbn_core_i18n_server_internal.mdx index 73f2e5fe7b7ab7..4f7eb52b4046dc 100644 --- a/api_docs/kbn_core_i18n_server_internal.mdx +++ b/api_docs/kbn_core_i18n_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-internal title: "@kbn/core-i18n-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-internal'] --- import kbnCoreI18nServerInternalObj from './kbn_core_i18n_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_i18n_server_mocks.mdx b/api_docs/kbn_core_i18n_server_mocks.mdx index 1315ef6891fccb..22f86912b81a3c 100644 --- a/api_docs/kbn_core_i18n_server_mocks.mdx +++ b/api_docs/kbn_core_i18n_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-i18n-server-mocks title: "@kbn/core-i18n-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-i18n-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-i18n-server-mocks'] --- import kbnCoreI18nServerMocksObj from './kbn_core_i18n_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx index a02d9d6fba3c44..8c41370ae05ce5 100644 --- a/api_docs/kbn_core_injected_metadata_browser_mocks.mdx +++ b/api_docs/kbn_core_injected_metadata_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-injected-metadata-browser-mocks title: "@kbn/core-injected-metadata-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-injected-metadata-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-injected-metadata-browser-mocks'] --- import kbnCoreInjectedMetadataBrowserMocksObj from './kbn_core_injected_metadata_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_internal.mdx b/api_docs/kbn_core_integrations_browser_internal.mdx index a9c1add7195b1c..83032fd5c40a89 100644 --- a/api_docs/kbn_core_integrations_browser_internal.mdx +++ b/api_docs/kbn_core_integrations_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-internal title: "@kbn/core-integrations-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-internal'] --- import kbnCoreIntegrationsBrowserInternalObj from './kbn_core_integrations_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_integrations_browser_mocks.mdx b/api_docs/kbn_core_integrations_browser_mocks.mdx index f5e17a8fa1fe23..b848941a7a7a54 100644 --- a/api_docs/kbn_core_integrations_browser_mocks.mdx +++ b/api_docs/kbn_core_integrations_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-integrations-browser-mocks title: "@kbn/core-integrations-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-integrations-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-integrations-browser-mocks'] --- import kbnCoreIntegrationsBrowserMocksObj from './kbn_core_integrations_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser.mdx b/api_docs/kbn_core_lifecycle_browser.mdx index c30864172c39a6..e1250e106ed518 100644 --- a/api_docs/kbn_core_lifecycle_browser.mdx +++ b/api_docs/kbn_core_lifecycle_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser title: "@kbn/core-lifecycle-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser'] --- import kbnCoreLifecycleBrowserObj from './kbn_core_lifecycle_browser.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_browser_mocks.mdx b/api_docs/kbn_core_lifecycle_browser_mocks.mdx index 9a202a38730a79..bac32c82d16fff 100644 --- a/api_docs/kbn_core_lifecycle_browser_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-browser-mocks title: "@kbn/core-lifecycle-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-browser-mocks'] --- import kbnCoreLifecycleBrowserMocksObj from './kbn_core_lifecycle_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server.mdx b/api_docs/kbn_core_lifecycle_server.mdx index 1942806fe22ed9..e0aebd355762be 100644 --- a/api_docs/kbn_core_lifecycle_server.mdx +++ b/api_docs/kbn_core_lifecycle_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server title: "@kbn/core-lifecycle-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server'] --- import kbnCoreLifecycleServerObj from './kbn_core_lifecycle_server.devdocs.json'; diff --git a/api_docs/kbn_core_lifecycle_server_mocks.mdx b/api_docs/kbn_core_lifecycle_server_mocks.mdx index ded5ebd5ff92ca..9e409c2b03599f 100644 --- a/api_docs/kbn_core_lifecycle_server_mocks.mdx +++ b/api_docs/kbn_core_lifecycle_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-lifecycle-server-mocks title: "@kbn/core-lifecycle-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-lifecycle-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-lifecycle-server-mocks'] --- import kbnCoreLifecycleServerMocksObj from './kbn_core_lifecycle_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_browser_mocks.mdx b/api_docs/kbn_core_logging_browser_mocks.mdx index a46cc5a542d8a4..4c6a6701771fa1 100644 --- a/api_docs/kbn_core_logging_browser_mocks.mdx +++ b/api_docs/kbn_core_logging_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-browser-mocks title: "@kbn/core-logging-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-browser-mocks'] --- import kbnCoreLoggingBrowserMocksObj from './kbn_core_logging_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_logging_common_internal.mdx b/api_docs/kbn_core_logging_common_internal.mdx index cf76f5036462e0..a26d3c67a77b3f 100644 --- a/api_docs/kbn_core_logging_common_internal.mdx +++ b/api_docs/kbn_core_logging_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-common-internal title: "@kbn/core-logging-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-common-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-common-internal'] --- import kbnCoreLoggingCommonInternalObj from './kbn_core_logging_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server.mdx b/api_docs/kbn_core_logging_server.mdx index eda2b9cb75ddef..2b37ec5717c6df 100644 --- a/api_docs/kbn_core_logging_server.mdx +++ b/api_docs/kbn_core_logging_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server title: "@kbn/core-logging-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server'] --- import kbnCoreLoggingServerObj from './kbn_core_logging_server.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_internal.mdx b/api_docs/kbn_core_logging_server_internal.mdx index 2ff635b6bbf52b..69c4baa523fa79 100644 --- a/api_docs/kbn_core_logging_server_internal.mdx +++ b/api_docs/kbn_core_logging_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-internal title: "@kbn/core-logging-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-internal'] --- import kbnCoreLoggingServerInternalObj from './kbn_core_logging_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_logging_server_mocks.mdx b/api_docs/kbn_core_logging_server_mocks.mdx index 56bb969c3350bf..40a5c317349a8d 100644 --- a/api_docs/kbn_core_logging_server_mocks.mdx +++ b/api_docs/kbn_core_logging_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-logging-server-mocks title: "@kbn/core-logging-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-logging-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-logging-server-mocks'] --- import kbnCoreLoggingServerMocksObj from './kbn_core_logging_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_internal.mdx b/api_docs/kbn_core_metrics_collectors_server_internal.mdx index 2f4ba5d7b8ef33..743bbd40b25e5d 100644 --- a/api_docs/kbn_core_metrics_collectors_server_internal.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-internal title: "@kbn/core-metrics-collectors-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-internal'] --- import kbnCoreMetricsCollectorsServerInternalObj from './kbn_core_metrics_collectors_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx index 0cd54045a37d9a..b5da1d017c0e44 100644 --- a/api_docs/kbn_core_metrics_collectors_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_collectors_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-collectors-server-mocks title: "@kbn/core-metrics-collectors-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-collectors-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-collectors-server-mocks'] --- import kbnCoreMetricsCollectorsServerMocksObj from './kbn_core_metrics_collectors_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server.mdx b/api_docs/kbn_core_metrics_server.mdx index 6a7dbdf75bf462..0a68c2eab4123f 100644 --- a/api_docs/kbn_core_metrics_server.mdx +++ b/api_docs/kbn_core_metrics_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server title: "@kbn/core-metrics-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server'] --- import kbnCoreMetricsServerObj from './kbn_core_metrics_server.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_internal.mdx b/api_docs/kbn_core_metrics_server_internal.mdx index a13c90fce33df1..e5dcd93170ad51 100644 --- a/api_docs/kbn_core_metrics_server_internal.mdx +++ b/api_docs/kbn_core_metrics_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-internal title: "@kbn/core-metrics-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-internal'] --- import kbnCoreMetricsServerInternalObj from './kbn_core_metrics_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_metrics_server_mocks.mdx b/api_docs/kbn_core_metrics_server_mocks.mdx index ab5fa599e7e3a6..7d264cccb8e795 100644 --- a/api_docs/kbn_core_metrics_server_mocks.mdx +++ b/api_docs/kbn_core_metrics_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-metrics-server-mocks title: "@kbn/core-metrics-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-metrics-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-metrics-server-mocks'] --- import kbnCoreMetricsServerMocksObj from './kbn_core_metrics_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_mount_utils_browser.mdx b/api_docs/kbn_core_mount_utils_browser.mdx index 192c840b454e80..bbac57db6e4c48 100644 --- a/api_docs/kbn_core_mount_utils_browser.mdx +++ b/api_docs/kbn_core_mount_utils_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-mount-utils-browser title: "@kbn/core-mount-utils-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-mount-utils-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-mount-utils-browser'] --- import kbnCoreMountUtilsBrowserObj from './kbn_core_mount_utils_browser.devdocs.json'; diff --git a/api_docs/kbn_core_node_server.mdx b/api_docs/kbn_core_node_server.mdx index 99f3a9615f4d2e..50c7095daecad5 100644 --- a/api_docs/kbn_core_node_server.mdx +++ b/api_docs/kbn_core_node_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server title: "@kbn/core-node-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server'] --- import kbnCoreNodeServerObj from './kbn_core_node_server.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_internal.mdx b/api_docs/kbn_core_node_server_internal.mdx index 44751ea15f344a..730fdab674600e 100644 --- a/api_docs/kbn_core_node_server_internal.mdx +++ b/api_docs/kbn_core_node_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-internal title: "@kbn/core-node-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-internal'] --- import kbnCoreNodeServerInternalObj from './kbn_core_node_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_node_server_mocks.mdx b/api_docs/kbn_core_node_server_mocks.mdx index 04a73321c78050..862f36858e0de0 100644 --- a/api_docs/kbn_core_node_server_mocks.mdx +++ b/api_docs/kbn_core_node_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-node-server-mocks title: "@kbn/core-node-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-node-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-node-server-mocks'] --- import kbnCoreNodeServerMocksObj from './kbn_core_node_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser.mdx b/api_docs/kbn_core_notifications_browser.mdx index caa866def90dca..44c83ee3c6dfc6 100644 --- a/api_docs/kbn_core_notifications_browser.mdx +++ b/api_docs/kbn_core_notifications_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser title: "@kbn/core-notifications-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser'] --- import kbnCoreNotificationsBrowserObj from './kbn_core_notifications_browser.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_internal.mdx b/api_docs/kbn_core_notifications_browser_internal.mdx index 462cefe1218662..47bb1e55560adc 100644 --- a/api_docs/kbn_core_notifications_browser_internal.mdx +++ b/api_docs/kbn_core_notifications_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-internal title: "@kbn/core-notifications-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-internal'] --- import kbnCoreNotificationsBrowserInternalObj from './kbn_core_notifications_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_notifications_browser_mocks.mdx b/api_docs/kbn_core_notifications_browser_mocks.mdx index 4d7f254acd8480..a73a74ba02395e 100644 --- a/api_docs/kbn_core_notifications_browser_mocks.mdx +++ b/api_docs/kbn_core_notifications_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-notifications-browser-mocks title: "@kbn/core-notifications-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-notifications-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-notifications-browser-mocks'] --- import kbnCoreNotificationsBrowserMocksObj from './kbn_core_notifications_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser.mdx b/api_docs/kbn_core_overlays_browser.mdx index 94219336995a36..6ac6010d2f5197 100644 --- a/api_docs/kbn_core_overlays_browser.mdx +++ b/api_docs/kbn_core_overlays_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser title: "@kbn/core-overlays-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser'] --- import kbnCoreOverlaysBrowserObj from './kbn_core_overlays_browser.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_internal.mdx b/api_docs/kbn_core_overlays_browser_internal.mdx index 2eb07733cd281f..705038ffaaeb96 100644 --- a/api_docs/kbn_core_overlays_browser_internal.mdx +++ b/api_docs/kbn_core_overlays_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-internal title: "@kbn/core-overlays-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-internal'] --- import kbnCoreOverlaysBrowserInternalObj from './kbn_core_overlays_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_overlays_browser_mocks.mdx b/api_docs/kbn_core_overlays_browser_mocks.mdx index 95c10a13417da8..d6101d5a218c85 100644 --- a/api_docs/kbn_core_overlays_browser_mocks.mdx +++ b/api_docs/kbn_core_overlays_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-overlays-browser-mocks title: "@kbn/core-overlays-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-overlays-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-overlays-browser-mocks'] --- import kbnCoreOverlaysBrowserMocksObj from './kbn_core_overlays_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser.mdx b/api_docs/kbn_core_plugins_browser.mdx index df6ed29c559c43..9936bea61e6404 100644 --- a/api_docs/kbn_core_plugins_browser.mdx +++ b/api_docs/kbn_core_plugins_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser title: "@kbn/core-plugins-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser'] --- import kbnCorePluginsBrowserObj from './kbn_core_plugins_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_browser_mocks.mdx b/api_docs/kbn_core_plugins_browser_mocks.mdx index d281e20bb01db1..1603b2ae9b554a 100644 --- a/api_docs/kbn_core_plugins_browser_mocks.mdx +++ b/api_docs/kbn_core_plugins_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-browser-mocks title: "@kbn/core-plugins-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-browser-mocks'] --- import kbnCorePluginsBrowserMocksObj from './kbn_core_plugins_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_browser.mdx b/api_docs/kbn_core_plugins_contracts_browser.mdx index ae40df7f23dcdb..36b6a058234495 100644 --- a/api_docs/kbn_core_plugins_contracts_browser.mdx +++ b/api_docs/kbn_core_plugins_contracts_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-browser title: "@kbn/core-plugins-contracts-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-browser'] --- import kbnCorePluginsContractsBrowserObj from './kbn_core_plugins_contracts_browser.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_contracts_server.mdx b/api_docs/kbn_core_plugins_contracts_server.mdx index 799d47fb45f820..0a8dc5d0bfe007 100644 --- a/api_docs/kbn_core_plugins_contracts_server.mdx +++ b/api_docs/kbn_core_plugins_contracts_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-contracts-server title: "@kbn/core-plugins-contracts-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-contracts-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-contracts-server'] --- import kbnCorePluginsContractsServerObj from './kbn_core_plugins_contracts_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server.mdx b/api_docs/kbn_core_plugins_server.mdx index a67b6fc8264e98..e17418a314e957 100644 --- a/api_docs/kbn_core_plugins_server.mdx +++ b/api_docs/kbn_core_plugins_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server title: "@kbn/core-plugins-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server'] --- import kbnCorePluginsServerObj from './kbn_core_plugins_server.devdocs.json'; diff --git a/api_docs/kbn_core_plugins_server_mocks.mdx b/api_docs/kbn_core_plugins_server_mocks.mdx index 28d198441f8143..c2eddaaa32c9fd 100644 --- a/api_docs/kbn_core_plugins_server_mocks.mdx +++ b/api_docs/kbn_core_plugins_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-plugins-server-mocks title: "@kbn/core-plugins-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-plugins-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-plugins-server-mocks'] --- import kbnCorePluginsServerMocksObj from './kbn_core_plugins_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server.mdx b/api_docs/kbn_core_preboot_server.mdx index 32ed09d1a75144..1772746154d23b 100644 --- a/api_docs/kbn_core_preboot_server.mdx +++ b/api_docs/kbn_core_preboot_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server title: "@kbn/core-preboot-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server'] --- import kbnCorePrebootServerObj from './kbn_core_preboot_server.devdocs.json'; diff --git a/api_docs/kbn_core_preboot_server_mocks.mdx b/api_docs/kbn_core_preboot_server_mocks.mdx index 97996dd6bff311..1aaf0b496105c1 100644 --- a/api_docs/kbn_core_preboot_server_mocks.mdx +++ b/api_docs/kbn_core_preboot_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-preboot-server-mocks title: "@kbn/core-preboot-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-preboot-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-preboot-server-mocks'] --- import kbnCorePrebootServerMocksObj from './kbn_core_preboot_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_browser_mocks.mdx b/api_docs/kbn_core_rendering_browser_mocks.mdx index 8f7cedfd580ee1..f196b14c28ff6c 100644 --- a/api_docs/kbn_core_rendering_browser_mocks.mdx +++ b/api_docs/kbn_core_rendering_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-browser-mocks title: "@kbn/core-rendering-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-browser-mocks'] --- import kbnCoreRenderingBrowserMocksObj from './kbn_core_rendering_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_internal.mdx b/api_docs/kbn_core_rendering_server_internal.mdx index 17d4535b843e42..a091fa79308f89 100644 --- a/api_docs/kbn_core_rendering_server_internal.mdx +++ b/api_docs/kbn_core_rendering_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-internal title: "@kbn/core-rendering-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-internal'] --- import kbnCoreRenderingServerInternalObj from './kbn_core_rendering_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_rendering_server_mocks.mdx b/api_docs/kbn_core_rendering_server_mocks.mdx index d9b0c2d075ae98..0cda032503ff59 100644 --- a/api_docs/kbn_core_rendering_server_mocks.mdx +++ b/api_docs/kbn_core_rendering_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-rendering-server-mocks title: "@kbn/core-rendering-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-rendering-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-rendering-server-mocks'] --- import kbnCoreRenderingServerMocksObj from './kbn_core_rendering_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_root_server_internal.mdx b/api_docs/kbn_core_root_server_internal.mdx index 7d607f561a9176..64c61f482f20ba 100644 --- a/api_docs/kbn_core_root_server_internal.mdx +++ b/api_docs/kbn_core_root_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-root-server-internal title: "@kbn/core-root-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-root-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-root-server-internal'] --- import kbnCoreRootServerInternalObj from './kbn_core_root_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_browser.mdx b/api_docs/kbn_core_saved_objects_api_browser.mdx index 32269d7399838d..37599d9d47bd7c 100644 --- a/api_docs/kbn_core_saved_objects_api_browser.mdx +++ b/api_docs/kbn_core_saved_objects_api_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-browser title: "@kbn/core-saved-objects-api-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-browser'] --- import kbnCoreSavedObjectsApiBrowserObj from './kbn_core_saved_objects_api_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server.mdx b/api_docs/kbn_core_saved_objects_api_server.mdx index 674325872d9c2c..cfe39fb7847b4f 100644 --- a/api_docs/kbn_core_saved_objects_api_server.mdx +++ b/api_docs/kbn_core_saved_objects_api_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server title: "@kbn/core-saved-objects-api-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server'] --- import kbnCoreSavedObjectsApiServerObj from './kbn_core_saved_objects_api_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx index 8628a694b4879d..58990c03d11688 100644 --- a/api_docs/kbn_core_saved_objects_api_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_api_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-api-server-mocks title: "@kbn/core-saved-objects-api-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-api-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-api-server-mocks'] --- import kbnCoreSavedObjectsApiServerMocksObj from './kbn_core_saved_objects_api_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_internal.mdx b/api_docs/kbn_core_saved_objects_base_server_internal.mdx index 803f7cca191f2d..ae32ef6bb3be86 100644 --- a/api_docs/kbn_core_saved_objects_base_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-internal title: "@kbn/core-saved-objects-base-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-internal'] --- import kbnCoreSavedObjectsBaseServerInternalObj from './kbn_core_saved_objects_base_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx index 3c8cea59acf786..d61e4a98ad2733 100644 --- a/api_docs/kbn_core_saved_objects_base_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_base_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-base-server-mocks title: "@kbn/core-saved-objects-base-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-base-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-base-server-mocks'] --- import kbnCoreSavedObjectsBaseServerMocksObj from './kbn_core_saved_objects_base_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser.mdx b/api_docs/kbn_core_saved_objects_browser.mdx index 63869267214d7e..60f1d025ffdb74 100644 --- a/api_docs/kbn_core_saved_objects_browser.mdx +++ b/api_docs/kbn_core_saved_objects_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser title: "@kbn/core-saved-objects-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser'] --- import kbnCoreSavedObjectsBrowserObj from './kbn_core_saved_objects_browser.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_internal.mdx b/api_docs/kbn_core_saved_objects_browser_internal.mdx index 7548eb34090b39..5801c5d79e2a62 100644 --- a/api_docs/kbn_core_saved_objects_browser_internal.mdx +++ b/api_docs/kbn_core_saved_objects_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-internal title: "@kbn/core-saved-objects-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-internal'] --- import kbnCoreSavedObjectsBrowserInternalObj from './kbn_core_saved_objects_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_browser_mocks.mdx b/api_docs/kbn_core_saved_objects_browser_mocks.mdx index 620fae71e8d282..f1e932f2cd5e0e 100644 --- a/api_docs/kbn_core_saved_objects_browser_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-browser-mocks title: "@kbn/core-saved-objects-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-browser-mocks'] --- import kbnCoreSavedObjectsBrowserMocksObj from './kbn_core_saved_objects_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_common.mdx b/api_docs/kbn_core_saved_objects_common.mdx index d32c235306b93b..023d4eaaaccdbe 100644 --- a/api_docs/kbn_core_saved_objects_common.mdx +++ b/api_docs/kbn_core_saved_objects_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-common title: "@kbn/core-saved-objects-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-common'] --- import kbnCoreSavedObjectsCommonObj from './kbn_core_saved_objects_common.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx index 9725217cbf98ba..a6f25810ab82d3 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-internal title: "@kbn/core-saved-objects-import-export-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-internal'] --- import kbnCoreSavedObjectsImportExportServerInternalObj from './kbn_core_saved_objects_import_export_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx index d7e4507a672aea..77ec587c3297b2 100644 --- a/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_import_export_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-import-export-server-mocks title: "@kbn/core-saved-objects-import-export-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-import-export-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-import-export-server-mocks'] --- import kbnCoreSavedObjectsImportExportServerMocksObj from './kbn_core_saved_objects_import_export_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx index 0a7a411bef49b8..9073d548b82164 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-internal title: "@kbn/core-saved-objects-migration-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-internal'] --- import kbnCoreSavedObjectsMigrationServerInternalObj from './kbn_core_saved_objects_migration_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx index c5dc09efc3abc8..9638ee5a931380 100644 --- a/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_migration_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-migration-server-mocks title: "@kbn/core-saved-objects-migration-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-migration-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-migration-server-mocks'] --- import kbnCoreSavedObjectsMigrationServerMocksObj from './kbn_core_saved_objects_migration_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server.mdx b/api_docs/kbn_core_saved_objects_server.mdx index 08b994a645416c..8bc9eb5c2ae4f1 100644 --- a/api_docs/kbn_core_saved_objects_server.mdx +++ b/api_docs/kbn_core_saved_objects_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server title: "@kbn/core-saved-objects-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server'] --- import kbnCoreSavedObjectsServerObj from './kbn_core_saved_objects_server.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_internal.mdx b/api_docs/kbn_core_saved_objects_server_internal.mdx index a1f148cd1d12f0..a0e4cc8b3f0714 100644 --- a/api_docs/kbn_core_saved_objects_server_internal.mdx +++ b/api_docs/kbn_core_saved_objects_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-internal title: "@kbn/core-saved-objects-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-internal'] --- import kbnCoreSavedObjectsServerInternalObj from './kbn_core_saved_objects_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_server_mocks.mdx b/api_docs/kbn_core_saved_objects_server_mocks.mdx index 6e7bef0bad4bb0..815315ab598089 100644 --- a/api_docs/kbn_core_saved_objects_server_mocks.mdx +++ b/api_docs/kbn_core_saved_objects_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-server-mocks title: "@kbn/core-saved-objects-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-server-mocks'] --- import kbnCoreSavedObjectsServerMocksObj from './kbn_core_saved_objects_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_saved_objects_utils_server.mdx b/api_docs/kbn_core_saved_objects_utils_server.mdx index 98a9083a4ba31e..e2613c01e69c26 100644 --- a/api_docs/kbn_core_saved_objects_utils_server.mdx +++ b/api_docs/kbn_core_saved_objects_utils_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-saved-objects-utils-server title: "@kbn/core-saved-objects-utils-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-saved-objects-utils-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-saved-objects-utils-server'] --- import kbnCoreSavedObjectsUtilsServerObj from './kbn_core_saved_objects_utils_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_common.mdx b/api_docs/kbn_core_status_common.mdx index 404d9c1f4f21ad..4419e685e49c3d 100644 --- a/api_docs/kbn_core_status_common.mdx +++ b/api_docs/kbn_core_status_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common title: "@kbn/core-status-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common'] --- import kbnCoreStatusCommonObj from './kbn_core_status_common.devdocs.json'; diff --git a/api_docs/kbn_core_status_common_internal.mdx b/api_docs/kbn_core_status_common_internal.mdx index c7a515b05602c5..78c11ff8df5c7c 100644 --- a/api_docs/kbn_core_status_common_internal.mdx +++ b/api_docs/kbn_core_status_common_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-common-internal title: "@kbn/core-status-common-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-common-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-common-internal'] --- import kbnCoreStatusCommonInternalObj from './kbn_core_status_common_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server.mdx b/api_docs/kbn_core_status_server.mdx index 12c342aafee443..8eb7a02c8173a0 100644 --- a/api_docs/kbn_core_status_server.mdx +++ b/api_docs/kbn_core_status_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server title: "@kbn/core-status-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server'] --- import kbnCoreStatusServerObj from './kbn_core_status_server.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_internal.mdx b/api_docs/kbn_core_status_server_internal.mdx index 56daf25b96dd37..7c10e0a04cf964 100644 --- a/api_docs/kbn_core_status_server_internal.mdx +++ b/api_docs/kbn_core_status_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-internal title: "@kbn/core-status-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-internal'] --- import kbnCoreStatusServerInternalObj from './kbn_core_status_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_status_server_mocks.mdx b/api_docs/kbn_core_status_server_mocks.mdx index b8c4709734c41e..4b90efa93a37c4 100644 --- a/api_docs/kbn_core_status_server_mocks.mdx +++ b/api_docs/kbn_core_status_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-status-server-mocks title: "@kbn/core-status-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-status-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-status-server-mocks'] --- import kbnCoreStatusServerMocksObj from './kbn_core_status_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx index fcd4c229030030..56f47df63581a3 100644 --- a/api_docs/kbn_core_test_helpers_deprecations_getters.mdx +++ b/api_docs/kbn_core_test_helpers_deprecations_getters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-deprecations-getters title: "@kbn/core-test-helpers-deprecations-getters" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-deprecations-getters plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-deprecations-getters'] --- import kbnCoreTestHelpersDeprecationsGettersObj from './kbn_core_test_helpers_deprecations_getters.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx index 96d3812f9840d2..058ced900a431b 100644 --- a/api_docs/kbn_core_test_helpers_http_setup_browser.mdx +++ b/api_docs/kbn_core_test_helpers_http_setup_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-http-setup-browser title: "@kbn/core-test-helpers-http-setup-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-http-setup-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-http-setup-browser'] --- import kbnCoreTestHelpersHttpSetupBrowserObj from './kbn_core_test_helpers_http_setup_browser.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_kbn_server.mdx b/api_docs/kbn_core_test_helpers_kbn_server.mdx index 7d9c601978838f..b535182d8d9d22 100644 --- a/api_docs/kbn_core_test_helpers_kbn_server.mdx +++ b/api_docs/kbn_core_test_helpers_kbn_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-kbn-server title: "@kbn/core-test-helpers-kbn-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-kbn-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-kbn-server'] --- import kbnCoreTestHelpersKbnServerObj from './kbn_core_test_helpers_kbn_server.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_model_versions.mdx b/api_docs/kbn_core_test_helpers_model_versions.mdx index e531bb54dd7a48..94c26caad2e4d9 100644 --- a/api_docs/kbn_core_test_helpers_model_versions.mdx +++ b/api_docs/kbn_core_test_helpers_model_versions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-model-versions title: "@kbn/core-test-helpers-model-versions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-model-versions plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-model-versions'] --- import kbnCoreTestHelpersModelVersionsObj from './kbn_core_test_helpers_model_versions.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx index 6e5bfac9881b71..960442097b3801 100644 --- a/api_docs/kbn_core_test_helpers_so_type_serializer.mdx +++ b/api_docs/kbn_core_test_helpers_so_type_serializer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-so-type-serializer title: "@kbn/core-test-helpers-so-type-serializer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-so-type-serializer plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-so-type-serializer'] --- import kbnCoreTestHelpersSoTypeSerializerObj from './kbn_core_test_helpers_so_type_serializer.devdocs.json'; diff --git a/api_docs/kbn_core_test_helpers_test_utils.mdx b/api_docs/kbn_core_test_helpers_test_utils.mdx index 12372d2e3007f8..34b77a5a8f2d33 100644 --- a/api_docs/kbn_core_test_helpers_test_utils.mdx +++ b/api_docs/kbn_core_test_helpers_test_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-test-helpers-test-utils title: "@kbn/core-test-helpers-test-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-test-helpers-test-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-test-helpers-test-utils'] --- import kbnCoreTestHelpersTestUtilsObj from './kbn_core_test_helpers_test_utils.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser.mdx b/api_docs/kbn_core_theme_browser.mdx index 548fb1b035c3f1..107ddef9d30d89 100644 --- a/api_docs/kbn_core_theme_browser.mdx +++ b/api_docs/kbn_core_theme_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser title: "@kbn/core-theme-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser'] --- import kbnCoreThemeBrowserObj from './kbn_core_theme_browser.devdocs.json'; diff --git a/api_docs/kbn_core_theme_browser_mocks.mdx b/api_docs/kbn_core_theme_browser_mocks.mdx index d0eea28f635ae5..9750724a368cc3 100644 --- a/api_docs/kbn_core_theme_browser_mocks.mdx +++ b/api_docs/kbn_core_theme_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-theme-browser-mocks title: "@kbn/core-theme-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-theme-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-theme-browser-mocks'] --- import kbnCoreThemeBrowserMocksObj from './kbn_core_theme_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser.mdx b/api_docs/kbn_core_ui_settings_browser.mdx index 6d3c94fd5ee20a..747566db261ec7 100644 --- a/api_docs/kbn_core_ui_settings_browser.mdx +++ b/api_docs/kbn_core_ui_settings_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser title: "@kbn/core-ui-settings-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser'] --- import kbnCoreUiSettingsBrowserObj from './kbn_core_ui_settings_browser.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_internal.mdx b/api_docs/kbn_core_ui_settings_browser_internal.mdx index 3f659401d8b412..07e0235d2a6b49 100644 --- a/api_docs/kbn_core_ui_settings_browser_internal.mdx +++ b/api_docs/kbn_core_ui_settings_browser_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-internal title: "@kbn/core-ui-settings-browser-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-internal'] --- import kbnCoreUiSettingsBrowserInternalObj from './kbn_core_ui_settings_browser_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_browser_mocks.mdx b/api_docs/kbn_core_ui_settings_browser_mocks.mdx index fefa2dec750184..c9ed2c19f572e7 100644 --- a/api_docs/kbn_core_ui_settings_browser_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_browser_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-browser-mocks title: "@kbn/core-ui-settings-browser-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-browser-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-browser-mocks'] --- import kbnCoreUiSettingsBrowserMocksObj from './kbn_core_ui_settings_browser_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_common.mdx b/api_docs/kbn_core_ui_settings_common.mdx index eb908d4fde0429..62886e924c7d67 100644 --- a/api_docs/kbn_core_ui_settings_common.mdx +++ b/api_docs/kbn_core_ui_settings_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-common title: "@kbn/core-ui-settings-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-common'] --- import kbnCoreUiSettingsCommonObj from './kbn_core_ui_settings_common.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server.mdx b/api_docs/kbn_core_ui_settings_server.mdx index 265e9138331d2c..7c1301f2c39bd8 100644 --- a/api_docs/kbn_core_ui_settings_server.mdx +++ b/api_docs/kbn_core_ui_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server title: "@kbn/core-ui-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server'] --- import kbnCoreUiSettingsServerObj from './kbn_core_ui_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_internal.mdx b/api_docs/kbn_core_ui_settings_server_internal.mdx index 6f775d031ec19e..519179adc37076 100644 --- a/api_docs/kbn_core_ui_settings_server_internal.mdx +++ b/api_docs/kbn_core_ui_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-internal title: "@kbn/core-ui-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-internal'] --- import kbnCoreUiSettingsServerInternalObj from './kbn_core_ui_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_ui_settings_server_mocks.mdx b/api_docs/kbn_core_ui_settings_server_mocks.mdx index dc80f64f4239dd..26ec3f817075e3 100644 --- a/api_docs/kbn_core_ui_settings_server_mocks.mdx +++ b/api_docs/kbn_core_ui_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-ui-settings-server-mocks title: "@kbn/core-ui-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-ui-settings-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-ui-settings-server-mocks'] --- import kbnCoreUiSettingsServerMocksObj from './kbn_core_ui_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server.mdx b/api_docs/kbn_core_usage_data_server.mdx index ff32124aed80d0..dbc8d02e63e466 100644 --- a/api_docs/kbn_core_usage_data_server.mdx +++ b/api_docs/kbn_core_usage_data_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server title: "@kbn/core-usage-data-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server'] --- import kbnCoreUsageDataServerObj from './kbn_core_usage_data_server.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_internal.mdx b/api_docs/kbn_core_usage_data_server_internal.mdx index a7e0cb9150a6b5..02a906770ea6df 100644 --- a/api_docs/kbn_core_usage_data_server_internal.mdx +++ b/api_docs/kbn_core_usage_data_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-internal title: "@kbn/core-usage-data-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-internal'] --- import kbnCoreUsageDataServerInternalObj from './kbn_core_usage_data_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_usage_data_server_mocks.mdx b/api_docs/kbn_core_usage_data_server_mocks.mdx index cc70e36d05b9e8..2f9898a018702c 100644 --- a/api_docs/kbn_core_usage_data_server_mocks.mdx +++ b/api_docs/kbn_core_usage_data_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-usage-data-server-mocks title: "@kbn/core-usage-data-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-usage-data-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-usage-data-server-mocks'] --- import kbnCoreUsageDataServerMocksObj from './kbn_core_usage_data_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server.mdx b/api_docs/kbn_core_user_settings_server.mdx index c7721a33b9c0cc..8bfb01a5612697 100644 --- a/api_docs/kbn_core_user_settings_server.mdx +++ b/api_docs/kbn_core_user_settings_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server title: "@kbn/core-user-settings-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server'] --- import kbnCoreUserSettingsServerObj from './kbn_core_user_settings_server.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_internal.mdx b/api_docs/kbn_core_user_settings_server_internal.mdx index 68c8b492f4a9a4..e8b3775eedfe81 100644 --- a/api_docs/kbn_core_user_settings_server_internal.mdx +++ b/api_docs/kbn_core_user_settings_server_internal.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-internal title: "@kbn/core-user-settings-server-internal" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-internal plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-internal'] --- import kbnCoreUserSettingsServerInternalObj from './kbn_core_user_settings_server_internal.devdocs.json'; diff --git a/api_docs/kbn_core_user_settings_server_mocks.mdx b/api_docs/kbn_core_user_settings_server_mocks.mdx index df0005a61f8784..e2e9e4a80ff0dc 100644 --- a/api_docs/kbn_core_user_settings_server_mocks.mdx +++ b/api_docs/kbn_core_user_settings_server_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-core-user-settings-server-mocks title: "@kbn/core-user-settings-server-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/core-user-settings-server-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/core-user-settings-server-mocks'] --- import kbnCoreUserSettingsServerMocksObj from './kbn_core_user_settings_server_mocks.devdocs.json'; diff --git a/api_docs/kbn_crypto.mdx b/api_docs/kbn_crypto.mdx index 2b2d477a80d41f..0ba4c15252d030 100644 --- a/api_docs/kbn_crypto.mdx +++ b/api_docs/kbn_crypto.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto title: "@kbn/crypto" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto'] --- import kbnCryptoObj from './kbn_crypto.devdocs.json'; diff --git a/api_docs/kbn_crypto_browser.mdx b/api_docs/kbn_crypto_browser.mdx index 4382fce60e8419..37f29fcf15bd83 100644 --- a/api_docs/kbn_crypto_browser.mdx +++ b/api_docs/kbn_crypto_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-crypto-browser title: "@kbn/crypto-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/crypto-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/crypto-browser'] --- import kbnCryptoBrowserObj from './kbn_crypto_browser.devdocs.json'; diff --git a/api_docs/kbn_custom_integrations.mdx b/api_docs/kbn_custom_integrations.mdx index 3a1013e6ed6da2..e3e259d6ece395 100644 --- a/api_docs/kbn_custom_integrations.mdx +++ b/api_docs/kbn_custom_integrations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-custom-integrations title: "@kbn/custom-integrations" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/custom-integrations plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/custom-integrations'] --- import kbnCustomIntegrationsObj from './kbn_custom_integrations.devdocs.json'; diff --git a/api_docs/kbn_cypress_config.mdx b/api_docs/kbn_cypress_config.mdx index 69b09a66af83c9..c601c1a62d8427 100644 --- a/api_docs/kbn_cypress_config.mdx +++ b/api_docs/kbn_cypress_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-cypress-config title: "@kbn/cypress-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/cypress-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/cypress-config'] --- import kbnCypressConfigObj from './kbn_cypress_config.devdocs.json'; diff --git a/api_docs/kbn_data_service.mdx b/api_docs/kbn_data_service.mdx index 83a44b34bd14a8..30aa67ca3f06ab 100644 --- a/api_docs/kbn_data_service.mdx +++ b/api_docs/kbn_data_service.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-data-service title: "@kbn/data-service" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/data-service plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/data-service'] --- import kbnDataServiceObj from './kbn_data_service.devdocs.json'; diff --git a/api_docs/kbn_datemath.mdx b/api_docs/kbn_datemath.mdx index 6fdc1a1b7a1a6b..2011f72523938e 100644 --- a/api_docs/kbn_datemath.mdx +++ b/api_docs/kbn_datemath.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-datemath title: "@kbn/datemath" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/datemath plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/datemath'] --- import kbnDatemathObj from './kbn_datemath.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_analytics.mdx b/api_docs/kbn_deeplinks_analytics.mdx index 0d670973ba89cd..bc69fa0a7b8987 100644 --- a/api_docs/kbn_deeplinks_analytics.mdx +++ b/api_docs/kbn_deeplinks_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-analytics title: "@kbn/deeplinks-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-analytics plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-analytics'] --- import kbnDeeplinksAnalyticsObj from './kbn_deeplinks_analytics.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_devtools.mdx b/api_docs/kbn_deeplinks_devtools.mdx index ef126c925ae0f9..69a2a0ae589310 100644 --- a/api_docs/kbn_deeplinks_devtools.mdx +++ b/api_docs/kbn_deeplinks_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-devtools title: "@kbn/deeplinks-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-devtools plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-devtools'] --- import kbnDeeplinksDevtoolsObj from './kbn_deeplinks_devtools.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_management.mdx b/api_docs/kbn_deeplinks_management.mdx index 748fc07f1fcb8b..18a18cdd1fb6f4 100644 --- a/api_docs/kbn_deeplinks_management.mdx +++ b/api_docs/kbn_deeplinks_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-management title: "@kbn/deeplinks-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-management plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-management'] --- import kbnDeeplinksManagementObj from './kbn_deeplinks_management.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_ml.mdx b/api_docs/kbn_deeplinks_ml.mdx index e619f363be0d87..e4a385eadec10d 100644 --- a/api_docs/kbn_deeplinks_ml.mdx +++ b/api_docs/kbn_deeplinks_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-ml title: "@kbn/deeplinks-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-ml plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-ml'] --- import kbnDeeplinksMlObj from './kbn_deeplinks_ml.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_observability.mdx b/api_docs/kbn_deeplinks_observability.mdx index 855e44ad02df2b..e774ec641f00f5 100644 --- a/api_docs/kbn_deeplinks_observability.mdx +++ b/api_docs/kbn_deeplinks_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-observability title: "@kbn/deeplinks-observability" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-observability plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-observability'] --- import kbnDeeplinksObservabilityObj from './kbn_deeplinks_observability.devdocs.json'; diff --git a/api_docs/kbn_deeplinks_search.mdx b/api_docs/kbn_deeplinks_search.mdx index 39dbac6785fa44..b14853d54c5868 100644 --- a/api_docs/kbn_deeplinks_search.mdx +++ b/api_docs/kbn_deeplinks_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-deeplinks-search title: "@kbn/deeplinks-search" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/deeplinks-search plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/deeplinks-search'] --- import kbnDeeplinksSearchObj from './kbn_deeplinks_search.devdocs.json'; diff --git a/api_docs/kbn_default_nav_analytics.mdx b/api_docs/kbn_default_nav_analytics.mdx index 534e0312f0dd62..9f4ecb954d14ff 100644 --- a/api_docs/kbn_default_nav_analytics.mdx +++ b/api_docs/kbn_default_nav_analytics.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-analytics title: "@kbn/default-nav-analytics" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-analytics plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-analytics'] --- import kbnDefaultNavAnalyticsObj from './kbn_default_nav_analytics.devdocs.json'; diff --git a/api_docs/kbn_default_nav_devtools.mdx b/api_docs/kbn_default_nav_devtools.mdx index ab6b14ef4b4ec9..8738588384e7a0 100644 --- a/api_docs/kbn_default_nav_devtools.mdx +++ b/api_docs/kbn_default_nav_devtools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-devtools title: "@kbn/default-nav-devtools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-devtools plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-devtools'] --- import kbnDefaultNavDevtoolsObj from './kbn_default_nav_devtools.devdocs.json'; diff --git a/api_docs/kbn_default_nav_management.mdx b/api_docs/kbn_default_nav_management.mdx index e6e4f393e5677d..59810787d09931 100644 --- a/api_docs/kbn_default_nav_management.mdx +++ b/api_docs/kbn_default_nav_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-management title: "@kbn/default-nav-management" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-management plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-management'] --- import kbnDefaultNavManagementObj from './kbn_default_nav_management.devdocs.json'; diff --git a/api_docs/kbn_default_nav_ml.mdx b/api_docs/kbn_default_nav_ml.mdx index 20ed6718b0baa1..e111471d588f1c 100644 --- a/api_docs/kbn_default_nav_ml.mdx +++ b/api_docs/kbn_default_nav_ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-default-nav-ml title: "@kbn/default-nav-ml" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/default-nav-ml plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/default-nav-ml'] --- import kbnDefaultNavMlObj from './kbn_default_nav_ml.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_errors.mdx b/api_docs/kbn_dev_cli_errors.mdx index 12dc84d7f7281a..e5f258fcc8dde4 100644 --- a/api_docs/kbn_dev_cli_errors.mdx +++ b/api_docs/kbn_dev_cli_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-errors title: "@kbn/dev-cli-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-errors plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-errors'] --- import kbnDevCliErrorsObj from './kbn_dev_cli_errors.devdocs.json'; diff --git a/api_docs/kbn_dev_cli_runner.mdx b/api_docs/kbn_dev_cli_runner.mdx index 3de56ebc37d432..717f0af674d57a 100644 --- a/api_docs/kbn_dev_cli_runner.mdx +++ b/api_docs/kbn_dev_cli_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-cli-runner title: "@kbn/dev-cli-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-cli-runner plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-cli-runner'] --- import kbnDevCliRunnerObj from './kbn_dev_cli_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_proc_runner.mdx b/api_docs/kbn_dev_proc_runner.mdx index 0615dbba7c89a4..1d599d000b9f27 100644 --- a/api_docs/kbn_dev_proc_runner.mdx +++ b/api_docs/kbn_dev_proc_runner.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-proc-runner title: "@kbn/dev-proc-runner" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-proc-runner plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-proc-runner'] --- import kbnDevProcRunnerObj from './kbn_dev_proc_runner.devdocs.json'; diff --git a/api_docs/kbn_dev_utils.mdx b/api_docs/kbn_dev_utils.mdx index eba88e67cafff1..6b415804568fe0 100644 --- a/api_docs/kbn_dev_utils.mdx +++ b/api_docs/kbn_dev_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dev-utils title: "@kbn/dev-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dev-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dev-utils'] --- import kbnDevUtilsObj from './kbn_dev_utils.devdocs.json'; diff --git a/api_docs/kbn_discover_utils.mdx b/api_docs/kbn_discover_utils.mdx index deca9a5c2bf019..715795909d61bb 100644 --- a/api_docs/kbn_discover_utils.mdx +++ b/api_docs/kbn_discover_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-discover-utils title: "@kbn/discover-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/discover-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/discover-utils'] --- import kbnDiscoverUtilsObj from './kbn_discover_utils.devdocs.json'; diff --git a/api_docs/kbn_doc_links.devdocs.json b/api_docs/kbn_doc_links.devdocs.json index 1fa3fb82ac0578..c7391407a995ab 100644 --- a/api_docs/kbn_doc_links.devdocs.json +++ b/api_docs/kbn_doc_links.devdocs.json @@ -560,7 +560,7 @@ "label": "query", "description": [], "signature": [ - "{ readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuery: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; }" + "{ readonly eql: string; readonly kueryQuerySyntax: string; readonly luceneQuery: string; readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; readonly queryESQL: string; }" ], "path": "packages/kbn-doc-links/src/types.ts", "deprecated": false, diff --git a/api_docs/kbn_doc_links.mdx b/api_docs/kbn_doc_links.mdx index 5f8df9e84100c6..babcbf14e98460 100644 --- a/api_docs/kbn_doc_links.mdx +++ b/api_docs/kbn_doc_links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-doc-links title: "@kbn/doc-links" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/doc-links plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/doc-links'] --- import kbnDocLinksObj from './kbn_doc_links.devdocs.json'; diff --git a/api_docs/kbn_docs_utils.mdx b/api_docs/kbn_docs_utils.mdx index 4cb7abfb1bc922..512d9536e8365f 100644 --- a/api_docs/kbn_docs_utils.mdx +++ b/api_docs/kbn_docs_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-docs-utils title: "@kbn/docs-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/docs-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/docs-utils'] --- import kbnDocsUtilsObj from './kbn_docs_utils.devdocs.json'; diff --git a/api_docs/kbn_dom_drag_drop.mdx b/api_docs/kbn_dom_drag_drop.mdx index 301795a18647ef..412b63a12f7dff 100644 --- a/api_docs/kbn_dom_drag_drop.mdx +++ b/api_docs/kbn_dom_drag_drop.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-dom-drag-drop title: "@kbn/dom-drag-drop" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/dom-drag-drop plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/dom-drag-drop'] --- import kbnDomDragDropObj from './kbn_dom_drag_drop.devdocs.json'; diff --git a/api_docs/kbn_ebt_tools.mdx b/api_docs/kbn_ebt_tools.mdx index d9be60b9a22525..caebbce9373ae5 100644 --- a/api_docs/kbn_ebt_tools.mdx +++ b/api_docs/kbn_ebt_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ebt-tools title: "@kbn/ebt-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ebt-tools plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ebt-tools'] --- import kbnEbtToolsObj from './kbn_ebt_tools.devdocs.json'; diff --git a/api_docs/kbn_ecs.mdx b/api_docs/kbn_ecs.mdx index 8e0244ab646ea8..7c6a04f2448889 100644 --- a/api_docs/kbn_ecs.mdx +++ b/api_docs/kbn_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs title: "@kbn/ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs'] --- import kbnEcsObj from './kbn_ecs.devdocs.json'; diff --git a/api_docs/kbn_ecs_data_quality_dashboard.mdx b/api_docs/kbn_ecs_data_quality_dashboard.mdx index abb2b0ca93c9b5..6d88b6d040dce9 100644 --- a/api_docs/kbn_ecs_data_quality_dashboard.mdx +++ b/api_docs/kbn_ecs_data_quality_dashboard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ecs-data-quality-dashboard title: "@kbn/ecs-data-quality-dashboard" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ecs-data-quality-dashboard plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ecs-data-quality-dashboard'] --- import kbnEcsDataQualityDashboardObj from './kbn_ecs_data_quality_dashboard.devdocs.json'; diff --git a/api_docs/kbn_elastic_assistant.mdx b/api_docs/kbn_elastic_assistant.mdx index 8d8ec7d297eb5e..4d70acf8f1ce5d 100644 --- a/api_docs/kbn_elastic_assistant.mdx +++ b/api_docs/kbn_elastic_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-elastic-assistant title: "@kbn/elastic-assistant" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/elastic-assistant plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/elastic-assistant'] --- import kbnElasticAssistantObj from './kbn_elastic_assistant.devdocs.json'; diff --git a/api_docs/kbn_es.mdx b/api_docs/kbn_es.mdx index d6e770b2fac711..74b7a1967f4e71 100644 --- a/api_docs/kbn_es.mdx +++ b/api_docs/kbn_es.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es title: "@kbn/es" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es'] --- import kbnEsObj from './kbn_es.devdocs.json'; diff --git a/api_docs/kbn_es_archiver.mdx b/api_docs/kbn_es_archiver.mdx index 4b39e3e173f9ff..9d68fb22e24eab 100644 --- a/api_docs/kbn_es_archiver.mdx +++ b/api_docs/kbn_es_archiver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-archiver title: "@kbn/es-archiver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-archiver plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-archiver'] --- import kbnEsArchiverObj from './kbn_es_archiver.devdocs.json'; diff --git a/api_docs/kbn_es_errors.mdx b/api_docs/kbn_es_errors.mdx index 64e4de05a3ceb9..cf62fe45064ce5 100644 --- a/api_docs/kbn_es_errors.mdx +++ b/api_docs/kbn_es_errors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-errors title: "@kbn/es-errors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-errors plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-errors'] --- import kbnEsErrorsObj from './kbn_es_errors.devdocs.json'; diff --git a/api_docs/kbn_es_query.mdx b/api_docs/kbn_es_query.mdx index ed04c4c9008e0a..3c7c743ae0cfd8 100644 --- a/api_docs/kbn_es_query.mdx +++ b/api_docs/kbn_es_query.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-query title: "@kbn/es-query" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-query plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-query'] --- import kbnEsQueryObj from './kbn_es_query.devdocs.json'; diff --git a/api_docs/kbn_es_types.mdx b/api_docs/kbn_es_types.mdx index d88224e8a88c51..81ac3f476b3c1c 100644 --- a/api_docs/kbn_es_types.mdx +++ b/api_docs/kbn_es_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-es-types title: "@kbn/es-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/es-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/es-types'] --- import kbnEsTypesObj from './kbn_es_types.devdocs.json'; diff --git a/api_docs/kbn_eslint_plugin_imports.mdx b/api_docs/kbn_eslint_plugin_imports.mdx index 37ee190795dbb5..9439527562e57a 100644 --- a/api_docs/kbn_eslint_plugin_imports.mdx +++ b/api_docs/kbn_eslint_plugin_imports.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-eslint-plugin-imports title: "@kbn/eslint-plugin-imports" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/eslint-plugin-imports plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/eslint-plugin-imports'] --- import kbnEslintPluginImportsObj from './kbn_eslint_plugin_imports.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_common.mdx b/api_docs/kbn_event_annotation_common.mdx index df985adefefb2a..96216e04dcb864 100644 --- a/api_docs/kbn_event_annotation_common.mdx +++ b/api_docs/kbn_event_annotation_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-common title: "@kbn/event-annotation-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-common'] --- import kbnEventAnnotationCommonObj from './kbn_event_annotation_common.devdocs.json'; diff --git a/api_docs/kbn_event_annotation_components.mdx b/api_docs/kbn_event_annotation_components.mdx index 3cb4ab84252af4..aceb2aa1120347 100644 --- a/api_docs/kbn_event_annotation_components.mdx +++ b/api_docs/kbn_event_annotation_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-event-annotation-components title: "@kbn/event-annotation-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/event-annotation-components plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/event-annotation-components'] --- import kbnEventAnnotationComponentsObj from './kbn_event_annotation_components.devdocs.json'; diff --git a/api_docs/kbn_expandable_flyout.mdx b/api_docs/kbn_expandable_flyout.mdx index f423a5236e9a4a..f45f4516a0b025 100644 --- a/api_docs/kbn_expandable_flyout.mdx +++ b/api_docs/kbn_expandable_flyout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-expandable-flyout title: "@kbn/expandable-flyout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/expandable-flyout plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/expandable-flyout'] --- import kbnExpandableFlyoutObj from './kbn_expandable_flyout.devdocs.json'; diff --git a/api_docs/kbn_field_types.mdx b/api_docs/kbn_field_types.mdx index 5dff54aabfc390..921389d38571a8 100644 --- a/api_docs/kbn_field_types.mdx +++ b/api_docs/kbn_field_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-types title: "@kbn/field-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-types'] --- import kbnFieldTypesObj from './kbn_field_types.devdocs.json'; diff --git a/api_docs/kbn_field_utils.devdocs.json b/api_docs/kbn_field_utils.devdocs.json index a5c8a7e9fa4759..2395c626c01830 100644 --- a/api_docs/kbn_field_utils.devdocs.json +++ b/api_docs/kbn_field_utils.devdocs.json @@ -543,6 +543,20 @@ "path": "packages/kbn-field-utils/src/types.ts", "deprecated": false, "trackAdoption": false + }, + { + "parentPluginId": "@kbn/field-utils", + "id": "def-common.FieldBase.conflictDescriptions", + "type": "Object", + "tags": [], + "label": "conflictDescriptions", + "description": [], + "signature": [ + "Record | undefined" + ], + "path": "packages/kbn-field-utils/src/types.ts", + "deprecated": false, + "trackAdoption": false } ], "initialIsOpen": false diff --git a/api_docs/kbn_field_utils.mdx b/api_docs/kbn_field_utils.mdx index 13da0c84d3c76b..c48b4264882e50 100644 --- a/api_docs/kbn_field_utils.mdx +++ b/api_docs/kbn_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-field-utils title: "@kbn/field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/field-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/field-utils'] --- import kbnFieldUtilsObj from './kbn_field_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 36 | 0 | 28 | 1 | +| 37 | 0 | 29 | 1 | ## Common diff --git a/api_docs/kbn_find_used_node_modules.mdx b/api_docs/kbn_find_used_node_modules.mdx index 3cc4054adb54e4..8873e38fda2035 100644 --- a/api_docs/kbn_find_used_node_modules.mdx +++ b/api_docs/kbn_find_used_node_modules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-find-used-node-modules title: "@kbn/find-used-node-modules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/find-used-node-modules plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/find-used-node-modules'] --- import kbnFindUsedNodeModulesObj from './kbn_find_used_node_modules.devdocs.json'; diff --git a/api_docs/kbn_ftr_common_functional_services.mdx b/api_docs/kbn_ftr_common_functional_services.mdx index 56165d4dec27cb..6e344f241e3fb1 100644 --- a/api_docs/kbn_ftr_common_functional_services.mdx +++ b/api_docs/kbn_ftr_common_functional_services.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ftr-common-functional-services title: "@kbn/ftr-common-functional-services" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ftr-common-functional-services plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ftr-common-functional-services'] --- import kbnFtrCommonFunctionalServicesObj from './kbn_ftr_common_functional_services.devdocs.json'; diff --git a/api_docs/kbn_generate.mdx b/api_docs/kbn_generate.mdx index 40551b83c15150..0f9bb8c3dff4c2 100644 --- a/api_docs/kbn_generate.mdx +++ b/api_docs/kbn_generate.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate title: "@kbn/generate" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate'] --- import kbnGenerateObj from './kbn_generate.devdocs.json'; diff --git a/api_docs/kbn_generate_console_definitions.mdx b/api_docs/kbn_generate_console_definitions.mdx index 9405a0a570c69e..6cb42c28e31548 100644 --- a/api_docs/kbn_generate_console_definitions.mdx +++ b/api_docs/kbn_generate_console_definitions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-console-definitions title: "@kbn/generate-console-definitions" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-console-definitions plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-console-definitions'] --- import kbnGenerateConsoleDefinitionsObj from './kbn_generate_console_definitions.devdocs.json'; diff --git a/api_docs/kbn_generate_csv.mdx b/api_docs/kbn_generate_csv.mdx index 7d7452a3643da5..4825d56264bdc8 100644 --- a/api_docs/kbn_generate_csv.mdx +++ b/api_docs/kbn_generate_csv.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv title: "@kbn/generate-csv" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv'] --- import kbnGenerateCsvObj from './kbn_generate_csv.devdocs.json'; diff --git a/api_docs/kbn_generate_csv_types.mdx b/api_docs/kbn_generate_csv_types.mdx index 41c08ea7429bf8..f1f97f97ff6d6d 100644 --- a/api_docs/kbn_generate_csv_types.mdx +++ b/api_docs/kbn_generate_csv_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-generate-csv-types title: "@kbn/generate-csv-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/generate-csv-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/generate-csv-types'] --- import kbnGenerateCsvTypesObj from './kbn_generate_csv_types.devdocs.json'; diff --git a/api_docs/kbn_guided_onboarding.mdx b/api_docs/kbn_guided_onboarding.mdx index 17abbd37328176..d7b098d975f2cc 100644 --- a/api_docs/kbn_guided_onboarding.mdx +++ b/api_docs/kbn_guided_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-guided-onboarding title: "@kbn/guided-onboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/guided-onboarding plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/guided-onboarding'] --- import kbnGuidedOnboardingObj from './kbn_guided_onboarding.devdocs.json'; diff --git a/api_docs/kbn_handlebars.mdx b/api_docs/kbn_handlebars.mdx index 51c548d6a5251c..8e3a84d0838fb5 100644 --- a/api_docs/kbn_handlebars.mdx +++ b/api_docs/kbn_handlebars.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-handlebars title: "@kbn/handlebars" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/handlebars plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/handlebars'] --- import kbnHandlebarsObj from './kbn_handlebars.devdocs.json'; diff --git a/api_docs/kbn_hapi_mocks.mdx b/api_docs/kbn_hapi_mocks.mdx index b158160881ffb3..066867ad0e764a 100644 --- a/api_docs/kbn_hapi_mocks.mdx +++ b/api_docs/kbn_hapi_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-hapi-mocks title: "@kbn/hapi-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/hapi-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/hapi-mocks'] --- import kbnHapiMocksObj from './kbn_hapi_mocks.devdocs.json'; diff --git a/api_docs/kbn_health_gateway_server.mdx b/api_docs/kbn_health_gateway_server.mdx index 99729b051f62c4..87fe2fa8d3f906 100644 --- a/api_docs/kbn_health_gateway_server.mdx +++ b/api_docs/kbn_health_gateway_server.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-health-gateway-server title: "@kbn/health-gateway-server" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/health-gateway-server plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/health-gateway-server'] --- import kbnHealthGatewayServerObj from './kbn_health_gateway_server.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_card.mdx b/api_docs/kbn_home_sample_data_card.mdx index 8644ac638d967d..c1faefde44ed38 100644 --- a/api_docs/kbn_home_sample_data_card.mdx +++ b/api_docs/kbn_home_sample_data_card.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-card title: "@kbn/home-sample-data-card" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-card plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-card'] --- import kbnHomeSampleDataCardObj from './kbn_home_sample_data_card.devdocs.json'; diff --git a/api_docs/kbn_home_sample_data_tab.mdx b/api_docs/kbn_home_sample_data_tab.mdx index 950bc3f5a8c3e6..31daf946023c37 100644 --- a/api_docs/kbn_home_sample_data_tab.mdx +++ b/api_docs/kbn_home_sample_data_tab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-home-sample-data-tab title: "@kbn/home-sample-data-tab" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/home-sample-data-tab plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/home-sample-data-tab'] --- import kbnHomeSampleDataTabObj from './kbn_home_sample_data_tab.devdocs.json'; diff --git a/api_docs/kbn_i18n.mdx b/api_docs/kbn_i18n.mdx index d2829f801013f0..5042bae20d3f8f 100644 --- a/api_docs/kbn_i18n.mdx +++ b/api_docs/kbn_i18n.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n title: "@kbn/i18n" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n'] --- import kbnI18nObj from './kbn_i18n.devdocs.json'; diff --git a/api_docs/kbn_i18n_react.mdx b/api_docs/kbn_i18n_react.mdx index eefae681e3765c..bdaed1bf1a27e8 100644 --- a/api_docs/kbn_i18n_react.mdx +++ b/api_docs/kbn_i18n_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-i18n-react title: "@kbn/i18n-react" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/i18n-react plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/i18n-react'] --- import kbnI18nReactObj from './kbn_i18n_react.devdocs.json'; diff --git a/api_docs/kbn_import_resolver.mdx b/api_docs/kbn_import_resolver.mdx index 1ca448aa3d0b72..15b0fd1aefd4e7 100644 --- a/api_docs/kbn_import_resolver.mdx +++ b/api_docs/kbn_import_resolver.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-import-resolver title: "@kbn/import-resolver" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/import-resolver plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/import-resolver'] --- import kbnImportResolverObj from './kbn_import_resolver.devdocs.json'; diff --git a/api_docs/kbn_infra_forge.mdx b/api_docs/kbn_infra_forge.mdx index e2dc1a05e82509..41f5e379ce018e 100644 --- a/api_docs/kbn_infra_forge.mdx +++ b/api_docs/kbn_infra_forge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-infra-forge title: "@kbn/infra-forge" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/infra-forge plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/infra-forge'] --- import kbnInfraForgeObj from './kbn_infra_forge.devdocs.json'; diff --git a/api_docs/kbn_interpreter.mdx b/api_docs/kbn_interpreter.mdx index ae517aa176a603..1227a3d3438561 100644 --- a/api_docs/kbn_interpreter.mdx +++ b/api_docs/kbn_interpreter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-interpreter title: "@kbn/interpreter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/interpreter plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/interpreter'] --- import kbnInterpreterObj from './kbn_interpreter.devdocs.json'; diff --git a/api_docs/kbn_io_ts_utils.mdx b/api_docs/kbn_io_ts_utils.mdx index 0ff48e688f5ffa..24755cd4e24b6f 100644 --- a/api_docs/kbn_io_ts_utils.mdx +++ b/api_docs/kbn_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-io-ts-utils title: "@kbn/io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/io-ts-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/io-ts-utils'] --- import kbnIoTsUtilsObj from './kbn_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_jest_serializers.mdx b/api_docs/kbn_jest_serializers.mdx index 8aa5fc0a3af23d..fa313dd2ef3df4 100644 --- a/api_docs/kbn_jest_serializers.mdx +++ b/api_docs/kbn_jest_serializers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-jest-serializers title: "@kbn/jest-serializers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/jest-serializers plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/jest-serializers'] --- import kbnJestSerializersObj from './kbn_jest_serializers.devdocs.json'; diff --git a/api_docs/kbn_journeys.mdx b/api_docs/kbn_journeys.mdx index cb2b680c373001..d49eb0a6edebc0 100644 --- a/api_docs/kbn_journeys.mdx +++ b/api_docs/kbn_journeys.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-journeys title: "@kbn/journeys" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/journeys plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/journeys'] --- import kbnJourneysObj from './kbn_journeys.devdocs.json'; diff --git a/api_docs/kbn_json_ast.mdx b/api_docs/kbn_json_ast.mdx index 90b89bc444a203..fe59f4f3ac668a 100644 --- a/api_docs/kbn_json_ast.mdx +++ b/api_docs/kbn_json_ast.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-json-ast title: "@kbn/json-ast" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/json-ast plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/json-ast'] --- import kbnJsonAstObj from './kbn_json_ast.devdocs.json'; diff --git a/api_docs/kbn_kibana_manifest_schema.mdx b/api_docs/kbn_kibana_manifest_schema.mdx index bc9e89caf79a31..902506da3a8834 100644 --- a/api_docs/kbn_kibana_manifest_schema.mdx +++ b/api_docs/kbn_kibana_manifest_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-kibana-manifest-schema title: "@kbn/kibana-manifest-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/kibana-manifest-schema plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/kibana-manifest-schema'] --- import kbnKibanaManifestSchemaObj from './kbn_kibana_manifest_schema.devdocs.json'; diff --git a/api_docs/kbn_language_documentation_popover.mdx b/api_docs/kbn_language_documentation_popover.mdx index 87208bec5fe4a6..165c64a109e78d 100644 --- a/api_docs/kbn_language_documentation_popover.mdx +++ b/api_docs/kbn_language_documentation_popover.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-language-documentation-popover title: "@kbn/language-documentation-popover" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/language-documentation-popover plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/language-documentation-popover'] --- import kbnLanguageDocumentationPopoverObj from './kbn_language_documentation_popover.devdocs.json'; diff --git a/api_docs/kbn_lens_embeddable_utils.mdx b/api_docs/kbn_lens_embeddable_utils.mdx index 705b0162825be9..8f146ebfbcdb62 100644 --- a/api_docs/kbn_lens_embeddable_utils.mdx +++ b/api_docs/kbn_lens_embeddable_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-lens-embeddable-utils title: "@kbn/lens-embeddable-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/lens-embeddable-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/lens-embeddable-utils'] --- import kbnLensEmbeddableUtilsObj from './kbn_lens_embeddable_utils.devdocs.json'; diff --git a/api_docs/kbn_logging.mdx b/api_docs/kbn_logging.mdx index 053b69d09ee9d7..14d11689d9f163 100644 --- a/api_docs/kbn_logging.mdx +++ b/api_docs/kbn_logging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging title: "@kbn/logging" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging'] --- import kbnLoggingObj from './kbn_logging.devdocs.json'; diff --git a/api_docs/kbn_logging_mocks.mdx b/api_docs/kbn_logging_mocks.mdx index 27529a5686ff29..716a0ffdd67942 100644 --- a/api_docs/kbn_logging_mocks.mdx +++ b/api_docs/kbn_logging_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-logging-mocks title: "@kbn/logging-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/logging-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/logging-mocks'] --- import kbnLoggingMocksObj from './kbn_logging_mocks.devdocs.json'; diff --git a/api_docs/kbn_managed_vscode_config.mdx b/api_docs/kbn_managed_vscode_config.mdx index d24f11d10b322f..cc9ba70961ef63 100644 --- a/api_docs/kbn_managed_vscode_config.mdx +++ b/api_docs/kbn_managed_vscode_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-managed-vscode-config title: "@kbn/managed-vscode-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/managed-vscode-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/managed-vscode-config'] --- import kbnManagedVscodeConfigObj from './kbn_managed_vscode_config.devdocs.json'; diff --git a/api_docs/kbn_management_cards_navigation.mdx b/api_docs/kbn_management_cards_navigation.mdx index ade85b97a97992..3fbda5b9bf5405 100644 --- a/api_docs/kbn_management_cards_navigation.mdx +++ b/api_docs/kbn_management_cards_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-cards-navigation title: "@kbn/management-cards-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-cards-navigation plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-cards-navigation'] --- import kbnManagementCardsNavigationObj from './kbn_management_cards_navigation.devdocs.json'; diff --git a/api_docs/kbn_management_settings_application.mdx b/api_docs/kbn_management_settings_application.mdx index 5ce3a64fd469b6..afe58694ea6b8c 100644 --- a/api_docs/kbn_management_settings_application.mdx +++ b/api_docs/kbn_management_settings_application.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-application title: "@kbn/management-settings-application" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-application plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-application'] --- import kbnManagementSettingsApplicationObj from './kbn_management_settings_application.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_category.mdx b/api_docs/kbn_management_settings_components_field_category.mdx index ab1351e488b786..a219d8e435fcf6 100644 --- a/api_docs/kbn_management_settings_components_field_category.mdx +++ b/api_docs/kbn_management_settings_components_field_category.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-category title: "@kbn/management-settings-components-field-category" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-category plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-category'] --- import kbnManagementSettingsComponentsFieldCategoryObj from './kbn_management_settings_components_field_category.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_input.mdx b/api_docs/kbn_management_settings_components_field_input.mdx index e7d3f88f5c5486..ac2f6c7ab08d50 100644 --- a/api_docs/kbn_management_settings_components_field_input.mdx +++ b/api_docs/kbn_management_settings_components_field_input.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-input title: "@kbn/management-settings-components-field-input" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-input plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-input'] --- import kbnManagementSettingsComponentsFieldInputObj from './kbn_management_settings_components_field_input.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_field_row.mdx b/api_docs/kbn_management_settings_components_field_row.mdx index 96f33f5994c984..9d5650a6ba7477 100644 --- a/api_docs/kbn_management_settings_components_field_row.mdx +++ b/api_docs/kbn_management_settings_components_field_row.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-field-row title: "@kbn/management-settings-components-field-row" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-field-row plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-field-row'] --- import kbnManagementSettingsComponentsFieldRowObj from './kbn_management_settings_components_field_row.devdocs.json'; diff --git a/api_docs/kbn_management_settings_components_form.mdx b/api_docs/kbn_management_settings_components_form.mdx index 7785914cb88407..09650391c13395 100644 --- a/api_docs/kbn_management_settings_components_form.mdx +++ b/api_docs/kbn_management_settings_components_form.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-components-form title: "@kbn/management-settings-components-form" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-components-form plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-components-form'] --- import kbnManagementSettingsComponentsFormObj from './kbn_management_settings_components_form.devdocs.json'; diff --git a/api_docs/kbn_management_settings_field_definition.mdx b/api_docs/kbn_management_settings_field_definition.mdx index fb8c5c7630be4a..1fd8770ec0bd2c 100644 --- a/api_docs/kbn_management_settings_field_definition.mdx +++ b/api_docs/kbn_management_settings_field_definition.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-field-definition title: "@kbn/management-settings-field-definition" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-field-definition plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-field-definition'] --- import kbnManagementSettingsFieldDefinitionObj from './kbn_management_settings_field_definition.devdocs.json'; diff --git a/api_docs/kbn_management_settings_ids.mdx b/api_docs/kbn_management_settings_ids.mdx index ce226861ff0f14..21ecebb535d89a 100644 --- a/api_docs/kbn_management_settings_ids.mdx +++ b/api_docs/kbn_management_settings_ids.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-ids title: "@kbn/management-settings-ids" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-ids plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-ids'] --- import kbnManagementSettingsIdsObj from './kbn_management_settings_ids.devdocs.json'; diff --git a/api_docs/kbn_management_settings_section_registry.mdx b/api_docs/kbn_management_settings_section_registry.mdx index d95e65d0a37d21..d945924026f63f 100644 --- a/api_docs/kbn_management_settings_section_registry.mdx +++ b/api_docs/kbn_management_settings_section_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-section-registry title: "@kbn/management-settings-section-registry" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-section-registry plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-section-registry'] --- import kbnManagementSettingsSectionRegistryObj from './kbn_management_settings_section_registry.devdocs.json'; diff --git a/api_docs/kbn_management_settings_types.mdx b/api_docs/kbn_management_settings_types.mdx index 66b94c758ebbf9..269a5c317d397e 100644 --- a/api_docs/kbn_management_settings_types.mdx +++ b/api_docs/kbn_management_settings_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-types title: "@kbn/management-settings-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-types'] --- import kbnManagementSettingsTypesObj from './kbn_management_settings_types.devdocs.json'; diff --git a/api_docs/kbn_management_settings_utilities.mdx b/api_docs/kbn_management_settings_utilities.mdx index 6ddf8127615923..a3cc17646effee 100644 --- a/api_docs/kbn_management_settings_utilities.mdx +++ b/api_docs/kbn_management_settings_utilities.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-settings-utilities title: "@kbn/management-settings-utilities" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-settings-utilities plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-settings-utilities'] --- import kbnManagementSettingsUtilitiesObj from './kbn_management_settings_utilities.devdocs.json'; diff --git a/api_docs/kbn_management_storybook_config.mdx b/api_docs/kbn_management_storybook_config.mdx index 420b3425df567e..8d5bfda904f3bc 100644 --- a/api_docs/kbn_management_storybook_config.mdx +++ b/api_docs/kbn_management_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-management-storybook-config title: "@kbn/management-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/management-storybook-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/management-storybook-config'] --- import kbnManagementStorybookConfigObj from './kbn_management_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_mapbox_gl.mdx b/api_docs/kbn_mapbox_gl.mdx index 2da04f0c0591e9..864c742c636351 100644 --- a/api_docs/kbn_mapbox_gl.mdx +++ b/api_docs/kbn_mapbox_gl.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-mapbox-gl title: "@kbn/mapbox-gl" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/mapbox-gl plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/mapbox-gl'] --- import kbnMapboxGlObj from './kbn_mapbox_gl.devdocs.json'; diff --git a/api_docs/kbn_maps_vector_tile_utils.mdx b/api_docs/kbn_maps_vector_tile_utils.mdx index e55ff2b77f09a8..929410ff05237f 100644 --- a/api_docs/kbn_maps_vector_tile_utils.mdx +++ b/api_docs/kbn_maps_vector_tile_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-maps-vector-tile-utils title: "@kbn/maps-vector-tile-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/maps-vector-tile-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/maps-vector-tile-utils'] --- import kbnMapsVectorTileUtilsObj from './kbn_maps_vector_tile_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_agg_utils.mdx b/api_docs/kbn_ml_agg_utils.mdx index 1b3eb36570ba1c..bf297728763f47 100644 --- a/api_docs/kbn_ml_agg_utils.mdx +++ b/api_docs/kbn_ml_agg_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-agg-utils title: "@kbn/ml-agg-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-agg-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-agg-utils'] --- import kbnMlAggUtilsObj from './kbn_ml_agg_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_anomaly_utils.mdx b/api_docs/kbn_ml_anomaly_utils.mdx index 984f2aac5e676d..b69e37751bcb4f 100644 --- a/api_docs/kbn_ml_anomaly_utils.mdx +++ b/api_docs/kbn_ml_anomaly_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-anomaly-utils title: "@kbn/ml-anomaly-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-anomaly-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-anomaly-utils'] --- import kbnMlAnomalyUtilsObj from './kbn_ml_anomaly_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_category_validator.mdx b/api_docs/kbn_ml_category_validator.mdx index 3ff52585053410..5c78bd2b049653 100644 --- a/api_docs/kbn_ml_category_validator.mdx +++ b/api_docs/kbn_ml_category_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-category-validator title: "@kbn/ml-category-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-category-validator plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-category-validator'] --- import kbnMlCategoryValidatorObj from './kbn_ml_category_validator.devdocs.json'; diff --git a/api_docs/kbn_ml_chi2test.mdx b/api_docs/kbn_ml_chi2test.mdx index 59d718271e1b8c..20378527c4ef2d 100644 --- a/api_docs/kbn_ml_chi2test.mdx +++ b/api_docs/kbn_ml_chi2test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-chi2test title: "@kbn/ml-chi2test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-chi2test plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-chi2test'] --- import kbnMlChi2testObj from './kbn_ml_chi2test.devdocs.json'; diff --git a/api_docs/kbn_ml_data_frame_analytics_utils.mdx b/api_docs/kbn_ml_data_frame_analytics_utils.mdx index 622e5457787f23..88e9ecea382dfa 100644 --- a/api_docs/kbn_ml_data_frame_analytics_utils.mdx +++ b/api_docs/kbn_ml_data_frame_analytics_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-frame-analytics-utils title: "@kbn/ml-data-frame-analytics-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-frame-analytics-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-frame-analytics-utils'] --- import kbnMlDataFrameAnalyticsUtilsObj from './kbn_ml_data_frame_analytics_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_data_grid.mdx b/api_docs/kbn_ml_data_grid.mdx index 59354995b1f7ab..956edaaf3a0ff7 100644 --- a/api_docs/kbn_ml_data_grid.mdx +++ b/api_docs/kbn_ml_data_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-data-grid title: "@kbn/ml-data-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-data-grid plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-data-grid'] --- import kbnMlDataGridObj from './kbn_ml_data_grid.devdocs.json'; diff --git a/api_docs/kbn_ml_date_picker.mdx b/api_docs/kbn_ml_date_picker.mdx index 77d0ae93903b02..3e210bbc6d1436 100644 --- a/api_docs/kbn_ml_date_picker.mdx +++ b/api_docs/kbn_ml_date_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-picker title: "@kbn/ml-date-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-picker plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-picker'] --- import kbnMlDatePickerObj from './kbn_ml_date_picker.devdocs.json'; diff --git a/api_docs/kbn_ml_date_utils.mdx b/api_docs/kbn_ml_date_utils.mdx index 0a05e4f4bd9ff4..078ba6204bd9eb 100644 --- a/api_docs/kbn_ml_date_utils.mdx +++ b/api_docs/kbn_ml_date_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-date-utils title: "@kbn/ml-date-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-date-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-date-utils'] --- import kbnMlDateUtilsObj from './kbn_ml_date_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_error_utils.mdx b/api_docs/kbn_ml_error_utils.mdx index d353119c91f567..b33448cbdf1032 100644 --- a/api_docs/kbn_ml_error_utils.mdx +++ b/api_docs/kbn_ml_error_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-error-utils title: "@kbn/ml-error-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-error-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-error-utils'] --- import kbnMlErrorUtilsObj from './kbn_ml_error_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_in_memory_table.mdx b/api_docs/kbn_ml_in_memory_table.mdx index 5c6ae82eee3485..a995ebf13d4721 100644 --- a/api_docs/kbn_ml_in_memory_table.mdx +++ b/api_docs/kbn_ml_in_memory_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-in-memory-table title: "@kbn/ml-in-memory-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-in-memory-table plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-in-memory-table'] --- import kbnMlInMemoryTableObj from './kbn_ml_in_memory_table.devdocs.json'; diff --git a/api_docs/kbn_ml_is_defined.mdx b/api_docs/kbn_ml_is_defined.mdx index ae3c9bb7197a96..cd9afaaf61e9c9 100644 --- a/api_docs/kbn_ml_is_defined.mdx +++ b/api_docs/kbn_ml_is_defined.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-defined title: "@kbn/ml-is-defined" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-defined plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-defined'] --- import kbnMlIsDefinedObj from './kbn_ml_is_defined.devdocs.json'; diff --git a/api_docs/kbn_ml_is_populated_object.mdx b/api_docs/kbn_ml_is_populated_object.mdx index 8442eae5f8fa0b..68462b3f4dd51a 100644 --- a/api_docs/kbn_ml_is_populated_object.mdx +++ b/api_docs/kbn_ml_is_populated_object.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-is-populated-object title: "@kbn/ml-is-populated-object" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-is-populated-object plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-is-populated-object'] --- import kbnMlIsPopulatedObjectObj from './kbn_ml_is_populated_object.devdocs.json'; diff --git a/api_docs/kbn_ml_kibana_theme.mdx b/api_docs/kbn_ml_kibana_theme.mdx index 700427ea218dde..62b2ccab478778 100644 --- a/api_docs/kbn_ml_kibana_theme.mdx +++ b/api_docs/kbn_ml_kibana_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-kibana-theme title: "@kbn/ml-kibana-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-kibana-theme plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-kibana-theme'] --- import kbnMlKibanaThemeObj from './kbn_ml_kibana_theme.devdocs.json'; diff --git a/api_docs/kbn_ml_local_storage.mdx b/api_docs/kbn_ml_local_storage.mdx index fcd5964cda87fe..6f2a5c02464a02 100644 --- a/api_docs/kbn_ml_local_storage.mdx +++ b/api_docs/kbn_ml_local_storage.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-local-storage title: "@kbn/ml-local-storage" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-local-storage plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-local-storage'] --- import kbnMlLocalStorageObj from './kbn_ml_local_storage.devdocs.json'; diff --git a/api_docs/kbn_ml_nested_property.mdx b/api_docs/kbn_ml_nested_property.mdx index 1e498750e9a567..be83bde1e30264 100644 --- a/api_docs/kbn_ml_nested_property.mdx +++ b/api_docs/kbn_ml_nested_property.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-nested-property title: "@kbn/ml-nested-property" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-nested-property plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-nested-property'] --- import kbnMlNestedPropertyObj from './kbn_ml_nested_property.devdocs.json'; diff --git a/api_docs/kbn_ml_number_utils.mdx b/api_docs/kbn_ml_number_utils.mdx index c6998a752b87ee..dec81bdbb2febb 100644 --- a/api_docs/kbn_ml_number_utils.mdx +++ b/api_docs/kbn_ml_number_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-number-utils title: "@kbn/ml-number-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-number-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-number-utils'] --- import kbnMlNumberUtilsObj from './kbn_ml_number_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_query_utils.mdx b/api_docs/kbn_ml_query_utils.mdx index 3cb8bd145a0da6..6d37904488851b 100644 --- a/api_docs/kbn_ml_query_utils.mdx +++ b/api_docs/kbn_ml_query_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-query-utils title: "@kbn/ml-query-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-query-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-query-utils'] --- import kbnMlQueryUtilsObj from './kbn_ml_query_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_random_sampler_utils.mdx b/api_docs/kbn_ml_random_sampler_utils.mdx index 471c178027c668..de6ac2901a88c8 100644 --- a/api_docs/kbn_ml_random_sampler_utils.mdx +++ b/api_docs/kbn_ml_random_sampler_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-random-sampler-utils title: "@kbn/ml-random-sampler-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-random-sampler-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-random-sampler-utils'] --- import kbnMlRandomSamplerUtilsObj from './kbn_ml_random_sampler_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_route_utils.mdx b/api_docs/kbn_ml_route_utils.mdx index bc95cd29eb7f2b..bae4fd56f7efaf 100644 --- a/api_docs/kbn_ml_route_utils.mdx +++ b/api_docs/kbn_ml_route_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-route-utils title: "@kbn/ml-route-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-route-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-route-utils'] --- import kbnMlRouteUtilsObj from './kbn_ml_route_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_runtime_field_utils.mdx b/api_docs/kbn_ml_runtime_field_utils.mdx index a1daa66c9f8e93..606300b10e496a 100644 --- a/api_docs/kbn_ml_runtime_field_utils.mdx +++ b/api_docs/kbn_ml_runtime_field_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-runtime-field-utils title: "@kbn/ml-runtime-field-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-runtime-field-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-runtime-field-utils'] --- import kbnMlRuntimeFieldUtilsObj from './kbn_ml_runtime_field_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_string_hash.mdx b/api_docs/kbn_ml_string_hash.mdx index 0787e9ab0e131d..419b0958c4f565 100644 --- a/api_docs/kbn_ml_string_hash.mdx +++ b/api_docs/kbn_ml_string_hash.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-string-hash title: "@kbn/ml-string-hash" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-string-hash plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-string-hash'] --- import kbnMlStringHashObj from './kbn_ml_string_hash.devdocs.json'; diff --git a/api_docs/kbn_ml_trained_models_utils.mdx b/api_docs/kbn_ml_trained_models_utils.mdx index c220ab52ed4190..1337db1a2a1017 100644 --- a/api_docs/kbn_ml_trained_models_utils.mdx +++ b/api_docs/kbn_ml_trained_models_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-trained-models-utils title: "@kbn/ml-trained-models-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-trained-models-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-trained-models-utils'] --- import kbnMlTrainedModelsUtilsObj from './kbn_ml_trained_models_utils.devdocs.json'; diff --git a/api_docs/kbn_ml_url_state.mdx b/api_docs/kbn_ml_url_state.mdx index bec061745f2ded..c9d8a19cd2ac18 100644 --- a/api_docs/kbn_ml_url_state.mdx +++ b/api_docs/kbn_ml_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ml-url-state title: "@kbn/ml-url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ml-url-state plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ml-url-state'] --- import kbnMlUrlStateObj from './kbn_ml_url_state.devdocs.json'; diff --git a/api_docs/kbn_monaco.mdx b/api_docs/kbn_monaco.mdx index 21250589e9a0d0..49a81da1e79ad8 100644 --- a/api_docs/kbn_monaco.mdx +++ b/api_docs/kbn_monaco.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-monaco title: "@kbn/monaco" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/monaco plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/monaco'] --- import kbnMonacoObj from './kbn_monaco.devdocs.json'; diff --git a/api_docs/kbn_object_versioning.mdx b/api_docs/kbn_object_versioning.mdx index ea4382215d0755..19ce5244ca7514 100644 --- a/api_docs/kbn_object_versioning.mdx +++ b/api_docs/kbn_object_versioning.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-object-versioning title: "@kbn/object-versioning" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/object-versioning plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/object-versioning'] --- import kbnObjectVersioningObj from './kbn_object_versioning.devdocs.json'; diff --git a/api_docs/kbn_observability_alert_details.mdx b/api_docs/kbn_observability_alert_details.mdx index 1ffd4b484babb5..e3c5dcbc1d9d61 100644 --- a/api_docs/kbn_observability_alert_details.mdx +++ b/api_docs/kbn_observability_alert_details.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alert-details title: "@kbn/observability-alert-details" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alert-details plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alert-details'] --- import kbnObservabilityAlertDetailsObj from './kbn_observability_alert_details.devdocs.json'; diff --git a/api_docs/kbn_observability_alerting_test_data.mdx b/api_docs/kbn_observability_alerting_test_data.mdx index 04e14eeccbc35e..572699ab406410 100644 --- a/api_docs/kbn_observability_alerting_test_data.mdx +++ b/api_docs/kbn_observability_alerting_test_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-observability-alerting-test-data title: "@kbn/observability-alerting-test-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/observability-alerting-test-data plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/observability-alerting-test-data'] --- import kbnObservabilityAlertingTestDataObj from './kbn_observability_alerting_test_data.devdocs.json'; diff --git a/api_docs/kbn_openapi_generator.mdx b/api_docs/kbn_openapi_generator.mdx index 3920c6c548893f..6e52a1b8a58779 100644 --- a/api_docs/kbn_openapi_generator.mdx +++ b/api_docs/kbn_openapi_generator.mdx @@ -8,14 +8,14 @@ slug: /kibana-dev-docs/api/kbn-openapi-generator title: "@kbn/openapi-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/openapi-generator plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/openapi-generator'] --- import kbnOpenapiGeneratorObj from './kbn_openapi_generator.devdocs.json'; -Contact [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) for questions regarding this plugin. +Contact [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) for questions regarding this plugin. **Code health stats** diff --git a/api_docs/kbn_optimizer.mdx b/api_docs/kbn_optimizer.mdx index 57decf2acb7a42..38b26317261957 100644 --- a/api_docs/kbn_optimizer.mdx +++ b/api_docs/kbn_optimizer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer title: "@kbn/optimizer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer'] --- import kbnOptimizerObj from './kbn_optimizer.devdocs.json'; diff --git a/api_docs/kbn_optimizer_webpack_helpers.mdx b/api_docs/kbn_optimizer_webpack_helpers.mdx index 3cb5c84284b511..42e40df00df81b 100644 --- a/api_docs/kbn_optimizer_webpack_helpers.mdx +++ b/api_docs/kbn_optimizer_webpack_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-optimizer-webpack-helpers title: "@kbn/optimizer-webpack-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/optimizer-webpack-helpers plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/optimizer-webpack-helpers'] --- import kbnOptimizerWebpackHelpersObj from './kbn_optimizer_webpack_helpers.devdocs.json'; diff --git a/api_docs/kbn_osquery_io_ts_types.mdx b/api_docs/kbn_osquery_io_ts_types.mdx index 114c2ed7c28dd6..b2d7c3620e9e00 100644 --- a/api_docs/kbn_osquery_io_ts_types.mdx +++ b/api_docs/kbn_osquery_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-osquery-io-ts-types title: "@kbn/osquery-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/osquery-io-ts-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/osquery-io-ts-types'] --- import kbnOsqueryIoTsTypesObj from './kbn_osquery_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_performance_testing_dataset_extractor.mdx b/api_docs/kbn_performance_testing_dataset_extractor.mdx index 2f99c321656789..c63d76a60799e0 100644 --- a/api_docs/kbn_performance_testing_dataset_extractor.mdx +++ b/api_docs/kbn_performance_testing_dataset_extractor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-performance-testing-dataset-extractor title: "@kbn/performance-testing-dataset-extractor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/performance-testing-dataset-extractor plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/performance-testing-dataset-extractor'] --- import kbnPerformanceTestingDatasetExtractorObj from './kbn_performance_testing_dataset_extractor.devdocs.json'; diff --git a/api_docs/kbn_plugin_generator.mdx b/api_docs/kbn_plugin_generator.mdx index 243617f2b59daf..ffd362345ec1c5 100644 --- a/api_docs/kbn_plugin_generator.mdx +++ b/api_docs/kbn_plugin_generator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-generator title: "@kbn/plugin-generator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-generator plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-generator'] --- import kbnPluginGeneratorObj from './kbn_plugin_generator.devdocs.json'; diff --git a/api_docs/kbn_plugin_helpers.mdx b/api_docs/kbn_plugin_helpers.mdx index 7cec5dfe085683..ddcccac5b84de4 100644 --- a/api_docs/kbn_plugin_helpers.mdx +++ b/api_docs/kbn_plugin_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-plugin-helpers title: "@kbn/plugin-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/plugin-helpers plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/plugin-helpers'] --- import kbnPluginHelpersObj from './kbn_plugin_helpers.devdocs.json'; diff --git a/api_docs/kbn_profiling_utils.mdx b/api_docs/kbn_profiling_utils.mdx index 35e3e643730163..cc550a43348dda 100644 --- a/api_docs/kbn_profiling_utils.mdx +++ b/api_docs/kbn_profiling_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-profiling-utils title: "@kbn/profiling-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/profiling-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/profiling-utils'] --- import kbnProfilingUtilsObj from './kbn_profiling_utils.devdocs.json'; diff --git a/api_docs/kbn_random_sampling.mdx b/api_docs/kbn_random_sampling.mdx index f73dad7b48f5aa..50d42a1981d6cb 100644 --- a/api_docs/kbn_random_sampling.mdx +++ b/api_docs/kbn_random_sampling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-random-sampling title: "@kbn/random-sampling" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/random-sampling plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/random-sampling'] --- import kbnRandomSamplingObj from './kbn_random_sampling.devdocs.json'; diff --git a/api_docs/kbn_react_field.mdx b/api_docs/kbn_react_field.mdx index 0f6c9ca3c8be14..bd3dc3bb4cff62 100644 --- a/api_docs/kbn_react_field.mdx +++ b/api_docs/kbn_react_field.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-field title: "@kbn/react-field" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-field plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-field'] --- import kbnReactFieldObj from './kbn_react_field.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_common.mdx b/api_docs/kbn_react_kibana_context_common.mdx index 97989ce4601d72..302e6ed081a1a5 100644 --- a/api_docs/kbn_react_kibana_context_common.mdx +++ b/api_docs/kbn_react_kibana_context_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-common title: "@kbn/react-kibana-context-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-common'] --- import kbnReactKibanaContextCommonObj from './kbn_react_kibana_context_common.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_render.mdx b/api_docs/kbn_react_kibana_context_render.mdx index 84de2cfb0a864f..a3e29de0a2f653 100644 --- a/api_docs/kbn_react_kibana_context_render.mdx +++ b/api_docs/kbn_react_kibana_context_render.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-render title: "@kbn/react-kibana-context-render" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-render plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-render'] --- import kbnReactKibanaContextRenderObj from './kbn_react_kibana_context_render.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_root.mdx b/api_docs/kbn_react_kibana_context_root.mdx index 7fa5b46a4dab9c..65435f53fd43a3 100644 --- a/api_docs/kbn_react_kibana_context_root.mdx +++ b/api_docs/kbn_react_kibana_context_root.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-root title: "@kbn/react-kibana-context-root" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-root plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-root'] --- import kbnReactKibanaContextRootObj from './kbn_react_kibana_context_root.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_styled.mdx b/api_docs/kbn_react_kibana_context_styled.mdx index 514e9189c3b5d9..22b9084b60c658 100644 --- a/api_docs/kbn_react_kibana_context_styled.mdx +++ b/api_docs/kbn_react_kibana_context_styled.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-styled title: "@kbn/react-kibana-context-styled" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-styled plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-styled'] --- import kbnReactKibanaContextStyledObj from './kbn_react_kibana_context_styled.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_context_theme.mdx b/api_docs/kbn_react_kibana_context_theme.mdx index e80d3edf8a5d56..1eeeb972552de0 100644 --- a/api_docs/kbn_react_kibana_context_theme.mdx +++ b/api_docs/kbn_react_kibana_context_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-context-theme title: "@kbn/react-kibana-context-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-context-theme plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-context-theme'] --- import kbnReactKibanaContextThemeObj from './kbn_react_kibana_context_theme.devdocs.json'; diff --git a/api_docs/kbn_react_kibana_mount.mdx b/api_docs/kbn_react_kibana_mount.mdx index e612cc0cf41a30..bba4af98419c72 100644 --- a/api_docs/kbn_react_kibana_mount.mdx +++ b/api_docs/kbn_react_kibana_mount.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-react-kibana-mount title: "@kbn/react-kibana-mount" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/react-kibana-mount plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/react-kibana-mount'] --- import kbnReactKibanaMountObj from './kbn_react_kibana_mount.devdocs.json'; diff --git a/api_docs/kbn_repo_file_maps.mdx b/api_docs/kbn_repo_file_maps.mdx index b903ad44518dc3..94a4bcb0414592 100644 --- a/api_docs/kbn_repo_file_maps.mdx +++ b/api_docs/kbn_repo_file_maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-file-maps title: "@kbn/repo-file-maps" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-file-maps plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-file-maps'] --- import kbnRepoFileMapsObj from './kbn_repo_file_maps.devdocs.json'; diff --git a/api_docs/kbn_repo_linter.mdx b/api_docs/kbn_repo_linter.mdx index 1e364892b3d5ee..a3d69135ed1ac2 100644 --- a/api_docs/kbn_repo_linter.mdx +++ b/api_docs/kbn_repo_linter.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-linter title: "@kbn/repo-linter" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-linter plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-linter'] --- import kbnRepoLinterObj from './kbn_repo_linter.devdocs.json'; diff --git a/api_docs/kbn_repo_path.mdx b/api_docs/kbn_repo_path.mdx index 2ad7159b787fe1..42e8e47c84a0f5 100644 --- a/api_docs/kbn_repo_path.mdx +++ b/api_docs/kbn_repo_path.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-path title: "@kbn/repo-path" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-path plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-path'] --- import kbnRepoPathObj from './kbn_repo_path.devdocs.json'; diff --git a/api_docs/kbn_repo_source_classifier.mdx b/api_docs/kbn_repo_source_classifier.mdx index e79f0133067151..a1c16c637a25e5 100644 --- a/api_docs/kbn_repo_source_classifier.mdx +++ b/api_docs/kbn_repo_source_classifier.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-repo-source-classifier title: "@kbn/repo-source-classifier" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/repo-source-classifier plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/repo-source-classifier'] --- import kbnRepoSourceClassifierObj from './kbn_repo_source_classifier.devdocs.json'; diff --git a/api_docs/kbn_reporting_common.mdx b/api_docs/kbn_reporting_common.mdx index 75ac7ebee0201b..6b2a514cd4f193 100644 --- a/api_docs/kbn_reporting_common.mdx +++ b/api_docs/kbn_reporting_common.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-reporting-common title: "@kbn/reporting-common" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/reporting-common plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/reporting-common'] --- import kbnReportingCommonObj from './kbn_reporting_common.devdocs.json'; diff --git a/api_docs/kbn_resizable_layout.mdx b/api_docs/kbn_resizable_layout.mdx index 17191d162a3d8b..0ba0b0d079b810 100644 --- a/api_docs/kbn_resizable_layout.mdx +++ b/api_docs/kbn_resizable_layout.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-resizable-layout title: "@kbn/resizable-layout" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/resizable-layout plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/resizable-layout'] --- import kbnResizableLayoutObj from './kbn_resizable_layout.devdocs.json'; diff --git a/api_docs/kbn_rison.mdx b/api_docs/kbn_rison.mdx index e5088146177807..2f6c0a4f0dcaa1 100644 --- a/api_docs/kbn_rison.mdx +++ b/api_docs/kbn_rison.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rison title: "@kbn/rison" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rison plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rison'] --- import kbnRisonObj from './kbn_rison.devdocs.json'; diff --git a/api_docs/kbn_rrule.mdx b/api_docs/kbn_rrule.mdx index a5532634e2aa95..1d7c3a76b30532 100644 --- a/api_docs/kbn_rrule.mdx +++ b/api_docs/kbn_rrule.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rrule title: "@kbn/rrule" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rrule plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rrule'] --- import kbnRruleObj from './kbn_rrule.devdocs.json'; diff --git a/api_docs/kbn_rule_data_utils.mdx b/api_docs/kbn_rule_data_utils.mdx index 3864a6a0ce4d0f..8644ffd9b8f93b 100644 --- a/api_docs/kbn_rule_data_utils.mdx +++ b/api_docs/kbn_rule_data_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-rule-data-utils title: "@kbn/rule-data-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/rule-data-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/rule-data-utils'] --- import kbnRuleDataUtilsObj from './kbn_rule_data_utils.devdocs.json'; diff --git a/api_docs/kbn_saved_objects_settings.mdx b/api_docs/kbn_saved_objects_settings.mdx index 287da2d5abd877..f91f8b28dbb8c8 100644 --- a/api_docs/kbn_saved_objects_settings.mdx +++ b/api_docs/kbn_saved_objects_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-saved-objects-settings title: "@kbn/saved-objects-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/saved-objects-settings plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/saved-objects-settings'] --- import kbnSavedObjectsSettingsObj from './kbn_saved_objects_settings.devdocs.json'; diff --git a/api_docs/kbn_search_api_panels.mdx b/api_docs/kbn_search_api_panels.mdx index 2f3c1534a59d73..33bf2dd7252a64 100644 --- a/api_docs/kbn_search_api_panels.mdx +++ b/api_docs/kbn_search_api_panels.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-api-panels title: "@kbn/search-api-panels" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-api-panels plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-api-panels'] --- import kbnSearchApiPanelsObj from './kbn_search_api_panels.devdocs.json'; diff --git a/api_docs/kbn_search_connectors.mdx b/api_docs/kbn_search_connectors.mdx index a07dc96086044a..541419836341ac 100644 --- a/api_docs/kbn_search_connectors.mdx +++ b/api_docs/kbn_search_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-connectors title: "@kbn/search-connectors" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-connectors plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-connectors'] --- import kbnSearchConnectorsObj from './kbn_search_connectors.devdocs.json'; diff --git a/api_docs/kbn_search_response_warnings.devdocs.json b/api_docs/kbn_search_response_warnings.devdocs.json index ecaeaa879e6994..ec2406fc599db5 100644 --- a/api_docs/kbn_search_response_warnings.devdocs.json +++ b/api_docs/kbn_search_response_warnings.devdocs.json @@ -56,47 +56,29 @@ }, { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.SearchResponseWarnings", + "id": "def-common.SearchResponseWarningsBadge", "type": "Function", - "tags": [ - "constructor" - ], - "label": "SearchResponseWarnings", - "description": [ - "\nSearchResponseWarnings component" - ], + "tags": [], + "label": "SearchResponseWarningsBadge", + "description": [], "signature": [ - "({ interceptedWarnings, variant, \"data-test-subj\": dataTestSubj, }: ", - { - "pluginId": "@kbn/search-response-warnings", - "scope": "common", - "docId": "kibKbnSearchResponseWarningsPluginApi", - "section": "def-common.SearchResponseWarningsProps", - "text": "SearchResponseWarningsProps" - }, - ") => JSX.Element | null" + "(props: Props) => JSX.Element | null" ], - "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx", + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/badge.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.SearchResponseWarnings.$1", + "id": "def-common.SearchResponseWarningsBadge.$1", "type": "Object", "tags": [], - "label": "{\n interceptedWarnings,\n variant,\n 'data-test-subj': dataTestSubj,\n}", + "label": "props", "description": [], "signature": [ - { - "pluginId": "@kbn/search-response-warnings", - "scope": "common", - "docId": "kibKbnSearchResponseWarningsPluginApi", - "section": "def-common.SearchResponseWarningsProps", - "text": "SearchResponseWarningsProps" - } + "Props" ], - "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx", + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/badge.tsx", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -107,23 +89,21 @@ }, { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.ViewWarningButton", + "id": "def-common.SearchResponseWarningsBadgePopoverContent", "type": "Function", "tags": [], - "label": "ViewWarningButton", + "label": "SearchResponseWarningsBadgePopoverContent", "description": [], "signature": [ - "(props: ", - "Props", - ") => JSX.Element" + "(props: Props) => JSX.Element" ], - "path": "packages/kbn-search-response-warnings/src/components/view_warning_button/index.tsx", + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/badge_popover_content.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.ViewWarningButton.$1", + "id": "def-common.SearchResponseWarningsBadgePopoverContent.$1", "type": "Object", "tags": [], "label": "props", @@ -131,7 +111,7 @@ "signature": [ "Props" ], - "path": "packages/kbn-search-response-warnings/src/components/view_warning_button/index.tsx", + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/badge_popover_content.tsx", "deprecated": false, "trackAdoption": false, "isRequired": true @@ -139,72 +119,75 @@ ], "returnComment": [], "initialIsOpen": false - } - ], - "interfaces": [ + }, { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.SearchResponseWarningsProps", - "type": "Interface", + "id": "def-common.SearchResponseWarningsCallout", + "type": "Function", "tags": [], - "label": "SearchResponseWarningsProps", - "description": [ - "\nSearchResponseWarnings component props" + "label": "SearchResponseWarningsCallout", + "description": [], + "signature": [ + "(props: Props) => JSX.Element | null" ], - "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx", + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/callout.tsx", "deprecated": false, "trackAdoption": false, "children": [ { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.SearchResponseWarningsProps.interceptedWarnings", - "type": "Array", + "id": "def-common.SearchResponseWarningsCallout.$1", + "type": "Object", "tags": [], - "label": "interceptedWarnings", - "description": [ - "\nAn array of warnings" - ], + "label": "props", + "description": [], "signature": [ - "SearchResponseIncompleteWarning", - "[] | undefined" + "Props" ], - "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx", + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/callout.tsx", "deprecated": false, - "trackAdoption": false - }, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/search-response-warnings", + "id": "def-common.SearchResponseWarningsEmptyPrompt", + "type": "Function", + "tags": [], + "label": "SearchResponseWarningsEmptyPrompt", + "description": [], + "signature": [ + "(props: Props) => JSX.Element" + ], + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/empty_prompt.tsx", + "deprecated": false, + "trackAdoption": false, + "children": [ { "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.SearchResponseWarningsProps.variant", - "type": "CompoundType", + "id": "def-common.SearchResponseWarningsEmptyPrompt.$1", + "type": "Object", "tags": [], - "label": "variant", - "description": [ - "\nView variant" - ], + "label": "props", + "description": [], "signature": [ - "\"callout\" | \"badge\" | \"empty_prompt\"" - ], - "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/search-response-warnings", - "id": "def-common.SearchResponseWarningsProps.datatestsubj", - "type": "string", - "tags": [], - "label": "'data-test-subj'", - "description": [ - "\nCustom data-test-subj value" + "Props" ], - "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx", + "path": "packages/kbn-search-response-warnings/src/components/search_response_warnings/empty_prompt.tsx", "deprecated": false, - "trackAdoption": false + "trackAdoption": false, + "isRequired": true } ], + "returnComment": [], "initialIsOpen": false } ], + "interfaces": [], "enums": [], "misc": [ { diff --git a/api_docs/kbn_search_response_warnings.mdx b/api_docs/kbn_search_response_warnings.mdx index 0bfd0eb4a58e99..65e416e0f9f4c4 100644 --- a/api_docs/kbn_search_response_warnings.mdx +++ b/api_docs/kbn_search_response_warnings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-search-response-warnings title: "@kbn/search-response-warnings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/search-response-warnings plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/search-response-warnings'] --- import kbnSearchResponseWarningsObj from './kbn_search_response_warnings.devdocs.json'; @@ -21,16 +21,13 @@ Contact [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/k | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 14 | 0 | 7 | 2 | +| 14 | 0 | 12 | 1 | ## Common ### Functions -### Interfaces - - ### Consts, variables and types diff --git a/api_docs/kbn_security_solution_features.mdx b/api_docs/kbn_security_solution_features.mdx index bb0156ad2b139c..4ec413587983ed 100644 --- a/api_docs/kbn_security_solution_features.mdx +++ b/api_docs/kbn_security_solution_features.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-features title: "@kbn/security-solution-features" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-features plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-features'] --- import kbnSecuritySolutionFeaturesObj from './kbn_security_solution_features.devdocs.json'; diff --git a/api_docs/kbn_security_solution_navigation.mdx b/api_docs/kbn_security_solution_navigation.mdx index d4f26e898fc7f0..e623a98c76c6ca 100644 --- a/api_docs/kbn_security_solution_navigation.mdx +++ b/api_docs/kbn_security_solution_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-navigation title: "@kbn/security-solution-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-navigation plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-navigation'] --- import kbnSecuritySolutionNavigationObj from './kbn_security_solution_navigation.devdocs.json'; diff --git a/api_docs/kbn_security_solution_side_nav.mdx b/api_docs/kbn_security_solution_side_nav.mdx index 174a7867f3909c..f861bf471c04d7 100644 --- a/api_docs/kbn_security_solution_side_nav.mdx +++ b/api_docs/kbn_security_solution_side_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-side-nav title: "@kbn/security-solution-side-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-side-nav plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-side-nav'] --- import kbnSecuritySolutionSideNavObj from './kbn_security_solution_side_nav.devdocs.json'; diff --git a/api_docs/kbn_security_solution_storybook_config.mdx b/api_docs/kbn_security_solution_storybook_config.mdx index 8ce101412ce7b9..0c6081427df419 100644 --- a/api_docs/kbn_security_solution_storybook_config.mdx +++ b/api_docs/kbn_security_solution_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-security-solution-storybook-config title: "@kbn/security-solution-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/security-solution-storybook-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/security-solution-storybook-config'] --- import kbnSecuritySolutionStorybookConfigObj from './kbn_security_solution_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_autocomplete.mdx b/api_docs/kbn_securitysolution_autocomplete.mdx index 02ec3245622375..1f78ef10f6976a 100644 --- a/api_docs/kbn_securitysolution_autocomplete.mdx +++ b/api_docs/kbn_securitysolution_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-autocomplete title: "@kbn/securitysolution-autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-autocomplete plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-autocomplete'] --- import kbnSecuritysolutionAutocompleteObj from './kbn_securitysolution_autocomplete.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_data_table.mdx b/api_docs/kbn_securitysolution_data_table.mdx index 43f278eaa229e7..d43f3db282eb40 100644 --- a/api_docs/kbn_securitysolution_data_table.mdx +++ b/api_docs/kbn_securitysolution_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-data-table title: "@kbn/securitysolution-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-data-table plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-data-table'] --- import kbnSecuritysolutionDataTableObj from './kbn_securitysolution_data_table.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_ecs.mdx b/api_docs/kbn_securitysolution_ecs.mdx index 67d65e344acf2a..258fb9e43e9392 100644 --- a/api_docs/kbn_securitysolution_ecs.mdx +++ b/api_docs/kbn_securitysolution_ecs.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-ecs title: "@kbn/securitysolution-ecs" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-ecs plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-ecs'] --- import kbnSecuritysolutionEcsObj from './kbn_securitysolution_ecs.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_es_utils.devdocs.json b/api_docs/kbn_securitysolution_es_utils.devdocs.json index ffa1a41949e972..89a04e0c6a4a4b 100644 --- a/api_docs/kbn_securitysolution_es_utils.devdocs.json +++ b/api_docs/kbn_securitysolution_es_utils.devdocs.json @@ -3819,39 +3819,6 @@ "returnComment": [], "initialIsOpen": false }, - { - "parentPluginId": "@kbn/securitysolution-es-utils", - "id": "def-common.stringifyZodError", - "type": "Function", - "tags": [], - "label": "stringifyZodError", - "description": [], - "signature": [ - "(err: Zod.ZodError) => string" - ], - "path": "packages/kbn-securitysolution-es-utils/src/transform_error/index.ts", - "deprecated": false, - "trackAdoption": false, - "children": [ - { - "parentPluginId": "@kbn/securitysolution-es-utils", - "id": "def-common.stringifyZodError.$1", - "type": "Object", - "tags": [], - "label": "err", - "description": [], - "signature": [ - "Zod.ZodError" - ], - "path": "packages/kbn-securitysolution-es-utils/src/transform_error/index.ts", - "deprecated": false, - "trackAdoption": false, - "isRequired": true - } - ], - "returnComment": [], - "initialIsOpen": false - }, { "parentPluginId": "@kbn/securitysolution-es-utils", "id": "def-common.transformError", diff --git a/api_docs/kbn_securitysolution_es_utils.mdx b/api_docs/kbn_securitysolution_es_utils.mdx index 3a9694c1281844..16beccbd6c79d8 100644 --- a/api_docs/kbn_securitysolution_es_utils.mdx +++ b/api_docs/kbn_securitysolution_es_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-es-utils title: "@kbn/securitysolution-es-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-es-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-es-utils'] --- import kbnSecuritysolutionEsUtilsObj from './kbn_securitysolution_es_utils.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-detection-engine](https://github.com/orgs/elastic/tea | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 89 | 0 | 78 | 1 | +| 87 | 0 | 76 | 1 | ## Common diff --git a/api_docs/kbn_securitysolution_exception_list_components.mdx b/api_docs/kbn_securitysolution_exception_list_components.mdx index bb5aedec7bc9a8..5259acc2b3dc12 100644 --- a/api_docs/kbn_securitysolution_exception_list_components.mdx +++ b/api_docs/kbn_securitysolution_exception_list_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-exception-list-components title: "@kbn/securitysolution-exception-list-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-exception-list-components plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-exception-list-components'] --- import kbnSecuritysolutionExceptionListComponentsObj from './kbn_securitysolution_exception_list_components.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_grouping.mdx b/api_docs/kbn_securitysolution_grouping.mdx index d2785ddb00d825..52cd92f1fede2f 100644 --- a/api_docs/kbn_securitysolution_grouping.mdx +++ b/api_docs/kbn_securitysolution_grouping.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-grouping title: "@kbn/securitysolution-grouping" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-grouping plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-grouping'] --- import kbnSecuritysolutionGroupingObj from './kbn_securitysolution_grouping.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_hook_utils.mdx b/api_docs/kbn_securitysolution_hook_utils.mdx index 8de7d2e302bb5d..5da2fd6c7a423e 100644 --- a/api_docs/kbn_securitysolution_hook_utils.mdx +++ b/api_docs/kbn_securitysolution_hook_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-hook-utils title: "@kbn/securitysolution-hook-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-hook-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-hook-utils'] --- import kbnSecuritysolutionHookUtilsObj from './kbn_securitysolution_hook_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx index 45dccbd2fdfd19..6d353d9799bd69 100644 --- a/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_alerting_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-alerting-types title: "@kbn/securitysolution-io-ts-alerting-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-alerting-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-alerting-types'] --- import kbnSecuritysolutionIoTsAlertingTypesObj from './kbn_securitysolution_io_ts_alerting_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_list_types.mdx b/api_docs/kbn_securitysolution_io_ts_list_types.mdx index c3503005a60357..ec0fb89843df9f 100644 --- a/api_docs/kbn_securitysolution_io_ts_list_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_list_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-list-types title: "@kbn/securitysolution-io-ts-list-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-list-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-list-types'] --- import kbnSecuritysolutionIoTsListTypesObj from './kbn_securitysolution_io_ts_list_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_types.mdx b/api_docs/kbn_securitysolution_io_ts_types.mdx index 2eb18ba2c9c871..797d23a27e965c 100644 --- a/api_docs/kbn_securitysolution_io_ts_types.mdx +++ b/api_docs/kbn_securitysolution_io_ts_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-types title: "@kbn/securitysolution-io-ts-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-types'] --- import kbnSecuritysolutionIoTsTypesObj from './kbn_securitysolution_io_ts_types.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_io_ts_utils.mdx b/api_docs/kbn_securitysolution_io_ts_utils.mdx index f07588e29d9a62..f0d9b7ca276ee6 100644 --- a/api_docs/kbn_securitysolution_io_ts_utils.mdx +++ b/api_docs/kbn_securitysolution_io_ts_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-io-ts-utils title: "@kbn/securitysolution-io-ts-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-io-ts-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-io-ts-utils'] --- import kbnSecuritysolutionIoTsUtilsObj from './kbn_securitysolution_io_ts_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_api.mdx b/api_docs/kbn_securitysolution_list_api.mdx index 1ddda084672739..c9eb3602fad196 100644 --- a/api_docs/kbn_securitysolution_list_api.mdx +++ b/api_docs/kbn_securitysolution_list_api.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-api title: "@kbn/securitysolution-list-api" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-api plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-api'] --- import kbnSecuritysolutionListApiObj from './kbn_securitysolution_list_api.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_constants.mdx b/api_docs/kbn_securitysolution_list_constants.mdx index e5e74e4e7b0a67..cfde284c834f89 100644 --- a/api_docs/kbn_securitysolution_list_constants.mdx +++ b/api_docs/kbn_securitysolution_list_constants.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-constants title: "@kbn/securitysolution-list-constants" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-constants plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-constants'] --- import kbnSecuritysolutionListConstantsObj from './kbn_securitysolution_list_constants.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_hooks.mdx b/api_docs/kbn_securitysolution_list_hooks.mdx index 5864cb6038fe3c..23afbb70502996 100644 --- a/api_docs/kbn_securitysolution_list_hooks.mdx +++ b/api_docs/kbn_securitysolution_list_hooks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-hooks title: "@kbn/securitysolution-list-hooks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-hooks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-hooks'] --- import kbnSecuritysolutionListHooksObj from './kbn_securitysolution_list_hooks.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_list_utils.mdx b/api_docs/kbn_securitysolution_list_utils.mdx index 16801530b03d98..4a62f862a142f4 100644 --- a/api_docs/kbn_securitysolution_list_utils.mdx +++ b/api_docs/kbn_securitysolution_list_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-list-utils title: "@kbn/securitysolution-list-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-list-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-list-utils'] --- import kbnSecuritysolutionListUtilsObj from './kbn_securitysolution_list_utils.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_rules.mdx b/api_docs/kbn_securitysolution_rules.mdx index 2149b054f2aaf2..2b57de4ce33288 100644 --- a/api_docs/kbn_securitysolution_rules.mdx +++ b/api_docs/kbn_securitysolution_rules.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-rules title: "@kbn/securitysolution-rules" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-rules plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-rules'] --- import kbnSecuritysolutionRulesObj from './kbn_securitysolution_rules.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_t_grid.mdx b/api_docs/kbn_securitysolution_t_grid.mdx index 05a29865b03b73..640c32a68c9694 100644 --- a/api_docs/kbn_securitysolution_t_grid.mdx +++ b/api_docs/kbn_securitysolution_t_grid.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-t-grid title: "@kbn/securitysolution-t-grid" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-t-grid plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-t-grid'] --- import kbnSecuritysolutionTGridObj from './kbn_securitysolution_t_grid.devdocs.json'; diff --git a/api_docs/kbn_securitysolution_utils.mdx b/api_docs/kbn_securitysolution_utils.mdx index e14356b61b3136..f51ffd9d79f388 100644 --- a/api_docs/kbn_securitysolution_utils.mdx +++ b/api_docs/kbn_securitysolution_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-securitysolution-utils title: "@kbn/securitysolution-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/securitysolution-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/securitysolution-utils'] --- import kbnSecuritysolutionUtilsObj from './kbn_securitysolution_utils.devdocs.json'; diff --git a/api_docs/kbn_server_http_tools.mdx b/api_docs/kbn_server_http_tools.mdx index 175ab1ecc5603b..73c5cb5e1366d2 100644 --- a/api_docs/kbn_server_http_tools.mdx +++ b/api_docs/kbn_server_http_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-http-tools title: "@kbn/server-http-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-http-tools plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-http-tools'] --- import kbnServerHttpToolsObj from './kbn_server_http_tools.devdocs.json'; diff --git a/api_docs/kbn_server_route_repository.mdx b/api_docs/kbn_server_route_repository.mdx index ecf7ce6464d357..2900ac23371b8e 100644 --- a/api_docs/kbn_server_route_repository.mdx +++ b/api_docs/kbn_server_route_repository.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-server-route-repository title: "@kbn/server-route-repository" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/server-route-repository plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/server-route-repository'] --- import kbnServerRouteRepositoryObj from './kbn_server_route_repository.devdocs.json'; diff --git a/api_docs/kbn_serverless_common_settings.mdx b/api_docs/kbn_serverless_common_settings.mdx index 8ac127ef47df43..64db5b2931bd62 100644 --- a/api_docs/kbn_serverless_common_settings.mdx +++ b/api_docs/kbn_serverless_common_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-common-settings title: "@kbn/serverless-common-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-common-settings plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-common-settings'] --- import kbnServerlessCommonSettingsObj from './kbn_serverless_common_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_observability_settings.mdx b/api_docs/kbn_serverless_observability_settings.mdx index 757a09c07c5a69..0c1c3d1a299106 100644 --- a/api_docs/kbn_serverless_observability_settings.mdx +++ b/api_docs/kbn_serverless_observability_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-observability-settings title: "@kbn/serverless-observability-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-observability-settings plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-observability-settings'] --- import kbnServerlessObservabilitySettingsObj from './kbn_serverless_observability_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_project_switcher.mdx b/api_docs/kbn_serverless_project_switcher.mdx index c74bcb5faee9cf..c6057ba517df25 100644 --- a/api_docs/kbn_serverless_project_switcher.mdx +++ b/api_docs/kbn_serverless_project_switcher.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-project-switcher title: "@kbn/serverless-project-switcher" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-project-switcher plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-project-switcher'] --- import kbnServerlessProjectSwitcherObj from './kbn_serverless_project_switcher.devdocs.json'; diff --git a/api_docs/kbn_serverless_search_settings.mdx b/api_docs/kbn_serverless_search_settings.mdx index 2301644ac720db..bc5822d9799853 100644 --- a/api_docs/kbn_serverless_search_settings.mdx +++ b/api_docs/kbn_serverless_search_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-search-settings title: "@kbn/serverless-search-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-search-settings plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-search-settings'] --- import kbnServerlessSearchSettingsObj from './kbn_serverless_search_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_security_settings.mdx b/api_docs/kbn_serverless_security_settings.mdx index 472c8db0a96b52..5c5d74f8b93a28 100644 --- a/api_docs/kbn_serverless_security_settings.mdx +++ b/api_docs/kbn_serverless_security_settings.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-security-settings title: "@kbn/serverless-security-settings" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-security-settings plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-security-settings'] --- import kbnServerlessSecuritySettingsObj from './kbn_serverless_security_settings.devdocs.json'; diff --git a/api_docs/kbn_serverless_storybook_config.mdx b/api_docs/kbn_serverless_storybook_config.mdx index 7345e64a62a4b6..742bbc58cd4a6c 100644 --- a/api_docs/kbn_serverless_storybook_config.mdx +++ b/api_docs/kbn_serverless_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-serverless-storybook-config title: "@kbn/serverless-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/serverless-storybook-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/serverless-storybook-config'] --- import kbnServerlessStorybookConfigObj from './kbn_serverless_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_svg.mdx b/api_docs/kbn_shared_svg.mdx index bdbcfdbb5493c3..28c4d567d7152d 100644 --- a/api_docs/kbn_shared_svg.mdx +++ b/api_docs/kbn_shared_svg.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-svg title: "@kbn/shared-svg" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-svg plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-svg'] --- import kbnSharedSvgObj from './kbn_shared_svg.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_avatar_solution.mdx b/api_docs/kbn_shared_ux_avatar_solution.mdx index 9af55e29ee46ef..920d67209f1e3b 100644 --- a/api_docs/kbn_shared_ux_avatar_solution.mdx +++ b/api_docs/kbn_shared_ux_avatar_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-avatar-solution title: "@kbn/shared-ux-avatar-solution" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-avatar-solution plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-avatar-solution'] --- import kbnSharedUxAvatarSolutionObj from './kbn_shared_ux_avatar_solution.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx index b06ba5c340315f..668e937459dbbe 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen title: "@kbn/shared-ux-button-exit-full-screen" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen'] --- import kbnSharedUxButtonExitFullScreenObj from './kbn_shared_ux_button_exit_full_screen.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx index 693e922c1cd6c4..b5192ce282b46d 100644 --- a/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx +++ b/api_docs/kbn_shared_ux_button_exit_full_screen_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-exit-full-screen-mocks title: "@kbn/shared-ux-button-exit-full-screen-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-exit-full-screen-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-exit-full-screen-mocks'] --- import kbnSharedUxButtonExitFullScreenMocksObj from './kbn_shared_ux_button_exit_full_screen_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_button_toolbar.mdx b/api_docs/kbn_shared_ux_button_toolbar.mdx index b6b36ac140e5f5..67e8cfabeda1a8 100644 --- a/api_docs/kbn_shared_ux_button_toolbar.mdx +++ b/api_docs/kbn_shared_ux_button_toolbar.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-button-toolbar title: "@kbn/shared-ux-button-toolbar" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-button-toolbar plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-button-toolbar'] --- import kbnSharedUxButtonToolbarObj from './kbn_shared_ux_button_toolbar.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data.mdx b/api_docs/kbn_shared_ux_card_no_data.mdx index 7519664a206e21..03a91034225d9e 100644 --- a/api_docs/kbn_shared_ux_card_no_data.mdx +++ b/api_docs/kbn_shared_ux_card_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data title: "@kbn/shared-ux-card-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data'] --- import kbnSharedUxCardNoDataObj from './kbn_shared_ux_card_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx index 2cf149d1f02a8e..424a0884c4f4f5 100644 --- a/api_docs/kbn_shared_ux_card_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_card_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-card-no-data-mocks title: "@kbn/shared-ux-card-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-card-no-data-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-card-no-data-mocks'] --- import kbnSharedUxCardNoDataMocksObj from './kbn_shared_ux_card_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json b/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json index 88da635df65c84..aeacbea9f98c0b 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json +++ b/api_docs/kbn_shared_ux_chrome_navigation.devdocs.json @@ -589,38 +589,6 @@ "deprecated": false, "trackAdoption": false }, - { - "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.GroupDefinition.defaultIsCollapsed", - "type": "CompoundType", - "tags": [], - "label": "defaultIsCollapsed", - "description": [ - "\nFlag to indicate if the group is initially collapsed or not.\n\n`undefined`: (Recommended) the group will be opened if any of its children nodes matches the current URL.\n\n`false`: the group will be opened event if none of its children nodes matches the current URL.\n\n`true`: the group will be collapsed event if any of its children nodes matches the current URL." - ], - "signature": [ - "boolean | undefined" - ], - "path": "packages/shared-ux/chrome/navigation/src/ui/types.ts", - "deprecated": false, - "trackAdoption": false - }, - { - "parentPluginId": "@kbn/shared-ux-chrome-navigation", - "id": "def-common.GroupDefinition.accordionProps", - "type": "Object", - "tags": [], - "label": "accordionProps", - "description": [], - "signature": [ - "Partial<", - "EuiAccordionProps", - "> | undefined" - ], - "path": "packages/shared-ux/chrome/navigation/src/ui/types.ts", - "deprecated": false, - "trackAdoption": false - }, { "parentPluginId": "@kbn/shared-ux-chrome-navigation", "id": "def-common.GroupDefinition.children", diff --git a/api_docs/kbn_shared_ux_chrome_navigation.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index 0da4f3b5addaf3..cb26bc75e3e36b 100644 --- a/api_docs/kbn_shared_ux_chrome_navigation.mdx +++ b/api_docs/kbn_shared_ux_chrome_navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-chrome-navigation title: "@kbn/shared-ux-chrome-navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-chrome-navigation plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 60 | 0 | 48 | 4 | +| 58 | 0 | 47 | 4 | ## Common diff --git a/api_docs/kbn_shared_ux_error_boundary.devdocs.json b/api_docs/kbn_shared_ux_error_boundary.devdocs.json index 9a660591878cc1..241648e48e5b54 100644 --- a/api_docs/kbn_shared_ux_error_boundary.devdocs.json +++ b/api_docs/kbn_shared_ux_error_boundary.devdocs.json @@ -90,6 +90,41 @@ ], "returnComment": [], "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/shared-ux-error-boundary", + "id": "def-common.ThrowIfError", + "type": "Function", + "tags": [], + "label": "ThrowIfError", + "description": [ + "\nThis component allows errors to be caught outside of a render tree, and re-thrown within a render tree\nwrapped by KibanaErrorBoundary. The purpose is to let KibanaErrorBoundary control the user experience when\nReact can not render due to an error.\n" + ], + "signature": [ + "({ error }: React.PropsWithChildren<{ error: Error | null; }>) => null" + ], + "path": "packages/shared-ux/error_boundary/src/ui/throw_if_error.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/shared-ux-error-boundary", + "id": "def-common.ThrowIfError.$1", + "type": "CompoundType", + "tags": [], + "label": "{ error }", + "description": [], + "signature": [ + "React.PropsWithChildren<{ error: Error | null; }>" + ], + "path": "packages/shared-ux/error_boundary/src/ui/throw_if_error.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false } ], "interfaces": [], diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index 516c037e2232d9..7bc3cb2043dd54 100644 --- a/api_docs/kbn_shared_ux_error_boundary.mdx +++ b/api_docs/kbn_shared_ux_error_boundary.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-error-boundary title: "@kbn/shared-ux-error-boundary" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-error-boundary plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sh | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 4 | 0 | 1 | 0 | +| 6 | 0 | 2 | 0 | ## Common diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 005c116558fccc..b52a850551f737 100644 --- a/api_docs/kbn_shared_ux_file_context.mdx +++ b/api_docs/kbn_shared_ux_file_context.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-context title: "@kbn/shared-ux-file-context" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-context plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-context'] --- import kbnSharedUxFileContextObj from './kbn_shared_ux_file_context.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image.mdx b/api_docs/kbn_shared_ux_file_image.mdx index b428de1f090ba9..61258dfb558231 100644 --- a/api_docs/kbn_shared_ux_file_image.mdx +++ b/api_docs/kbn_shared_ux_file_image.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image title: "@kbn/shared-ux-file-image" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image'] --- import kbnSharedUxFileImageObj from './kbn_shared_ux_file_image.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_image_mocks.mdx b/api_docs/kbn_shared_ux_file_image_mocks.mdx index e8f994a3cf7249..3f71d534362cae 100644 --- a/api_docs/kbn_shared_ux_file_image_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_image_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-image-mocks title: "@kbn/shared-ux-file-image-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-image-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-image-mocks'] --- import kbnSharedUxFileImageMocksObj from './kbn_shared_ux_file_image_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_mocks.mdx b/api_docs/kbn_shared_ux_file_mocks.mdx index 4b6dd25c25a5f1..0e3d255eb4b773 100644 --- a/api_docs/kbn_shared_ux_file_mocks.mdx +++ b/api_docs/kbn_shared_ux_file_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-mocks title: "@kbn/shared-ux-file-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-mocks'] --- import kbnSharedUxFileMocksObj from './kbn_shared_ux_file_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_picker.mdx b/api_docs/kbn_shared_ux_file_picker.mdx index 14c7c9abc33bc7..9a6c5e93f84d65 100644 --- a/api_docs/kbn_shared_ux_file_picker.mdx +++ b/api_docs/kbn_shared_ux_file_picker.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-picker title: "@kbn/shared-ux-file-picker" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-picker plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-picker'] --- import kbnSharedUxFilePickerObj from './kbn_shared_ux_file_picker.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_types.mdx b/api_docs/kbn_shared_ux_file_types.mdx index 3ce6c8d03c2d9e..00de447c9a1510 100644 --- a/api_docs/kbn_shared_ux_file_types.mdx +++ b/api_docs/kbn_shared_ux_file_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-types title: "@kbn/shared-ux-file-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-types'] --- import kbnSharedUxFileTypesObj from './kbn_shared_ux_file_types.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_upload.mdx b/api_docs/kbn_shared_ux_file_upload.mdx index a16ab0ee1bc7bb..b83a3cacc48082 100644 --- a/api_docs/kbn_shared_ux_file_upload.mdx +++ b/api_docs/kbn_shared_ux_file_upload.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-upload title: "@kbn/shared-ux-file-upload" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-upload plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-upload'] --- import kbnSharedUxFileUploadObj from './kbn_shared_ux_file_upload.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_util.mdx b/api_docs/kbn_shared_ux_file_util.mdx index 083c987c659dea..26023c8ec583b7 100644 --- a/api_docs/kbn_shared_ux_file_util.mdx +++ b/api_docs/kbn_shared_ux_file_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-file-util title: "@kbn/shared-ux-file-util" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-file-util plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-file-util'] --- import kbnSharedUxFileUtilObj from './kbn_shared_ux_file_util.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app.mdx b/api_docs/kbn_shared_ux_link_redirect_app.mdx index d4fed3dd617acc..cb36a085386462 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app title: "@kbn/shared-ux-link-redirect-app" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app'] --- import kbnSharedUxLinkRedirectAppObj from './kbn_shared_ux_link_redirect_app.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx index 491e40b817dfca..79cd0329eead26 100644 --- a/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx +++ b/api_docs/kbn_shared_ux_link_redirect_app_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-link-redirect-app-mocks title: "@kbn/shared-ux-link-redirect-app-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-link-redirect-app-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-link-redirect-app-mocks'] --- import kbnSharedUxLinkRedirectAppMocksObj from './kbn_shared_ux_link_redirect_app_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown.mdx b/api_docs/kbn_shared_ux_markdown.mdx index 050b48dbb45950..74629580fb779f 100644 --- a/api_docs/kbn_shared_ux_markdown.mdx +++ b/api_docs/kbn_shared_ux_markdown.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown title: "@kbn/shared-ux-markdown" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown'] --- import kbnSharedUxMarkdownObj from './kbn_shared_ux_markdown.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_markdown_mocks.mdx b/api_docs/kbn_shared_ux_markdown_mocks.mdx index ba8646647200e8..796ce4eab0459f 100644 --- a/api_docs/kbn_shared_ux_markdown_mocks.mdx +++ b/api_docs/kbn_shared_ux_markdown_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-markdown-mocks title: "@kbn/shared-ux-markdown-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-markdown-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-markdown-mocks'] --- import kbnSharedUxMarkdownMocksObj from './kbn_shared_ux_markdown_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx index dff3c127635e49..d81ff4badb4a11 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data title: "@kbn/shared-ux-page-analytics-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data'] --- import kbnSharedUxPageAnalyticsNoDataObj from './kbn_shared_ux_page_analytics_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx index 95ffc4f15693ec..9226dcb77286a5 100644 --- a/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_analytics_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-analytics-no-data-mocks title: "@kbn/shared-ux-page-analytics-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-analytics-no-data-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-analytics-no-data-mocks'] --- import kbnSharedUxPageAnalyticsNoDataMocksObj from './kbn_shared_ux_page_analytics_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx index e9cda3ec22a5a8..dd81315adcfbb7 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data title: "@kbn/shared-ux-page-kibana-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data'] --- import kbnSharedUxPageKibanaNoDataObj from './kbn_shared_ux_page_kibana_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx index 65601bbd6646bd..91728912c49d0d 100644 --- a/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-no-data-mocks title: "@kbn/shared-ux-page-kibana-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-no-data-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-no-data-mocks'] --- import kbnSharedUxPageKibanaNoDataMocksObj from './kbn_shared_ux_page_kibana_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template.mdx b/api_docs/kbn_shared_ux_page_kibana_template.mdx index 7307cefc31b06a..a28689654ec089 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template title: "@kbn/shared-ux-page-kibana-template" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template'] --- import kbnSharedUxPageKibanaTemplateObj from './kbn_shared_ux_page_kibana_template.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx index a4f1b15f2c94db..12f6de44b3660e 100644 --- a/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_kibana_template_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-kibana-template-mocks title: "@kbn/shared-ux-page-kibana-template-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-kibana-template-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-kibana-template-mocks'] --- import kbnSharedUxPageKibanaTemplateMocksObj from './kbn_shared_ux_page_kibana_template_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data.mdx b/api_docs/kbn_shared_ux_page_no_data.mdx index b145a24f19558d..be3759cc7996e7 100644 --- a/api_docs/kbn_shared_ux_page_no_data.mdx +++ b/api_docs/kbn_shared_ux_page_no_data.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data title: "@kbn/shared-ux-page-no-data" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data'] --- import kbnSharedUxPageNoDataObj from './kbn_shared_ux_page_no_data.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config.mdx b/api_docs/kbn_shared_ux_page_no_data_config.mdx index a7866430518769..fe3769fa2d5d0f 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config title: "@kbn/shared-ux-page-no-data-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config'] --- import kbnSharedUxPageNoDataConfigObj from './kbn_shared_ux_page_no_data_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx index 0a49c87e88affe..1b1b18da04ca14 100644 --- a/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_config_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-config-mocks title: "@kbn/shared-ux-page-no-data-config-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-config-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-config-mocks'] --- import kbnSharedUxPageNoDataConfigMocksObj from './kbn_shared_ux_page_no_data_config_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx index c0a68b44dff24c..e57aca8c49d85d 100644 --- a/api_docs/kbn_shared_ux_page_no_data_mocks.mdx +++ b/api_docs/kbn_shared_ux_page_no_data_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-no-data-mocks title: "@kbn/shared-ux-page-no-data-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-no-data-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-no-data-mocks'] --- import kbnSharedUxPageNoDataMocksObj from './kbn_shared_ux_page_no_data_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_page_solution_nav.mdx b/api_docs/kbn_shared_ux_page_solution_nav.mdx index 3f16f63b9c0def..beaf7e07214848 100644 --- a/api_docs/kbn_shared_ux_page_solution_nav.mdx +++ b/api_docs/kbn_shared_ux_page_solution_nav.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-page-solution-nav title: "@kbn/shared-ux-page-solution-nav" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-page-solution-nav plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-page-solution-nav'] --- import kbnSharedUxPageSolutionNavObj from './kbn_shared_ux_page_solution_nav.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx index 235bb4a364b75c..7cb3836142962a 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views title: "@kbn/shared-ux-prompt-no-data-views" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views'] --- import kbnSharedUxPromptNoDataViewsObj from './kbn_shared_ux_prompt_no_data_views.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx index 7a0aa078af69fa..85001675a413cb 100644 --- a/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx +++ b/api_docs/kbn_shared_ux_prompt_no_data_views_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-no-data-views-mocks title: "@kbn/shared-ux-prompt-no-data-views-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-no-data-views-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-no-data-views-mocks'] --- import kbnSharedUxPromptNoDataViewsMocksObj from './kbn_shared_ux_prompt_no_data_views_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_prompt_not_found.mdx b/api_docs/kbn_shared_ux_prompt_not_found.mdx index 201b7f33689627..cd90e79c9f7d70 100644 --- a/api_docs/kbn_shared_ux_prompt_not_found.mdx +++ b/api_docs/kbn_shared_ux_prompt_not_found.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-prompt-not-found title: "@kbn/shared-ux-prompt-not-found" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-prompt-not-found plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-prompt-not-found'] --- import kbnSharedUxPromptNotFoundObj from './kbn_shared_ux_prompt_not_found.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router.mdx b/api_docs/kbn_shared_ux_router.mdx index ba7ae79cf8ac7b..6f2f905b9b91fa 100644 --- a/api_docs/kbn_shared_ux_router.mdx +++ b/api_docs/kbn_shared_ux_router.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router title: "@kbn/shared-ux-router" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router'] --- import kbnSharedUxRouterObj from './kbn_shared_ux_router.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_router_mocks.mdx b/api_docs/kbn_shared_ux_router_mocks.mdx index 358337ffc4feb9..bf9c205d725c16 100644 --- a/api_docs/kbn_shared_ux_router_mocks.mdx +++ b/api_docs/kbn_shared_ux_router_mocks.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-router-mocks title: "@kbn/shared-ux-router-mocks" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-router-mocks plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-router-mocks'] --- import kbnSharedUxRouterMocksObj from './kbn_shared_ux_router_mocks.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_config.mdx b/api_docs/kbn_shared_ux_storybook_config.mdx index c0eb10ac736853..5b1feccace7a4c 100644 --- a/api_docs/kbn_shared_ux_storybook_config.mdx +++ b/api_docs/kbn_shared_ux_storybook_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-config title: "@kbn/shared-ux-storybook-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-config'] --- import kbnSharedUxStorybookConfigObj from './kbn_shared_ux_storybook_config.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_storybook_mock.mdx b/api_docs/kbn_shared_ux_storybook_mock.mdx index 3ba887db2cc99b..42438bd09c2669 100644 --- a/api_docs/kbn_shared_ux_storybook_mock.mdx +++ b/api_docs/kbn_shared_ux_storybook_mock.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-storybook-mock title: "@kbn/shared-ux-storybook-mock" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-storybook-mock plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-storybook-mock'] --- import kbnSharedUxStorybookMockObj from './kbn_shared_ux_storybook_mock.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_utility.mdx b/api_docs/kbn_shared_ux_utility.mdx index a38535dfa63e43..9831d1ac98474b 100644 --- a/api_docs/kbn_shared_ux_utility.mdx +++ b/api_docs/kbn_shared_ux_utility.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-shared-ux-utility title: "@kbn/shared-ux-utility" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/shared-ux-utility plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-utility'] --- import kbnSharedUxUtilityObj from './kbn_shared_ux_utility.devdocs.json'; diff --git a/api_docs/kbn_slo_schema.mdx b/api_docs/kbn_slo_schema.mdx index 995daee75bb86d..df5189b7cd1b77 100644 --- a/api_docs/kbn_slo_schema.mdx +++ b/api_docs/kbn_slo_schema.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-slo-schema title: "@kbn/slo-schema" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/slo-schema plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/slo-schema'] --- import kbnSloSchemaObj from './kbn_slo_schema.devdocs.json'; diff --git a/api_docs/kbn_some_dev_log.mdx b/api_docs/kbn_some_dev_log.mdx index 0ec39af0936ef1..5e93bc42448136 100644 --- a/api_docs/kbn_some_dev_log.mdx +++ b/api_docs/kbn_some_dev_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-some-dev-log title: "@kbn/some-dev-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/some-dev-log plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/some-dev-log'] --- import kbnSomeDevLogObj from './kbn_some_dev_log.devdocs.json'; diff --git a/api_docs/kbn_std.mdx b/api_docs/kbn_std.mdx index 20dc9bfd4be434..2e5365597dd9b6 100644 --- a/api_docs/kbn_std.mdx +++ b/api_docs/kbn_std.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-std title: "@kbn/std" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/std plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/std'] --- import kbnStdObj from './kbn_std.devdocs.json'; diff --git a/api_docs/kbn_stdio_dev_helpers.mdx b/api_docs/kbn_stdio_dev_helpers.mdx index a35cda9b245fe8..112edc5d56bad5 100644 --- a/api_docs/kbn_stdio_dev_helpers.mdx +++ b/api_docs/kbn_stdio_dev_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-stdio-dev-helpers title: "@kbn/stdio-dev-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/stdio-dev-helpers plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/stdio-dev-helpers'] --- import kbnStdioDevHelpersObj from './kbn_stdio_dev_helpers.devdocs.json'; diff --git a/api_docs/kbn_storybook.mdx b/api_docs/kbn_storybook.mdx index 0d6148f50ea004..094416a2d64340 100644 --- a/api_docs/kbn_storybook.mdx +++ b/api_docs/kbn_storybook.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-storybook title: "@kbn/storybook" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/storybook plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/storybook'] --- import kbnStorybookObj from './kbn_storybook.devdocs.json'; diff --git a/api_docs/kbn_subscription_tracking.mdx b/api_docs/kbn_subscription_tracking.mdx index 16261764b69219..190f29e354d2bd 100644 --- a/api_docs/kbn_subscription_tracking.mdx +++ b/api_docs/kbn_subscription_tracking.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-subscription-tracking title: "@kbn/subscription-tracking" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/subscription-tracking plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/subscription-tracking'] --- import kbnSubscriptionTrackingObj from './kbn_subscription_tracking.devdocs.json'; diff --git a/api_docs/kbn_telemetry_tools.mdx b/api_docs/kbn_telemetry_tools.mdx index a13e1300eaeb27..4841b1590198a0 100644 --- a/api_docs/kbn_telemetry_tools.mdx +++ b/api_docs/kbn_telemetry_tools.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-telemetry-tools title: "@kbn/telemetry-tools" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/telemetry-tools plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/telemetry-tools'] --- import kbnTelemetryToolsObj from './kbn_telemetry_tools.devdocs.json'; diff --git a/api_docs/kbn_test.mdx b/api_docs/kbn_test.mdx index ef111f0c91c4a3..777533b819c312 100644 --- a/api_docs/kbn_test.mdx +++ b/api_docs/kbn_test.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test title: "@kbn/test" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test'] --- import kbnTestObj from './kbn_test.devdocs.json'; diff --git a/api_docs/kbn_test_jest_helpers.mdx b/api_docs/kbn_test_jest_helpers.mdx index 3a2c83906186a3..caefb43a02de39 100644 --- a/api_docs/kbn_test_jest_helpers.mdx +++ b/api_docs/kbn_test_jest_helpers.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-jest-helpers title: "@kbn/test-jest-helpers" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-jest-helpers plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-jest-helpers'] --- import kbnTestJestHelpersObj from './kbn_test_jest_helpers.devdocs.json'; diff --git a/api_docs/kbn_test_subj_selector.mdx b/api_docs/kbn_test_subj_selector.mdx index 2b64306e7c857c..2011a0d76fda00 100644 --- a/api_docs/kbn_test_subj_selector.mdx +++ b/api_docs/kbn_test_subj_selector.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-test-subj-selector title: "@kbn/test-subj-selector" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/test-subj-selector plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/test-subj-selector'] --- import kbnTestSubjSelectorObj from './kbn_test_subj_selector.devdocs.json'; diff --git a/api_docs/kbn_text_based_editor.mdx b/api_docs/kbn_text_based_editor.mdx index 997fa96063829f..468eb0653e5bd4 100644 --- a/api_docs/kbn_text_based_editor.mdx +++ b/api_docs/kbn_text_based_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-text-based-editor title: "@kbn/text-based-editor" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/text-based-editor plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/text-based-editor'] --- import kbnTextBasedEditorObj from './kbn_text_based_editor.devdocs.json'; diff --git a/api_docs/kbn_tooling_log.mdx b/api_docs/kbn_tooling_log.mdx index ae23f0e7cf9e31..5b6bf12c84b2d7 100644 --- a/api_docs/kbn_tooling_log.mdx +++ b/api_docs/kbn_tooling_log.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-tooling-log title: "@kbn/tooling-log" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/tooling-log plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/tooling-log'] --- import kbnToolingLogObj from './kbn_tooling_log.devdocs.json'; diff --git a/api_docs/kbn_ts_projects.mdx b/api_docs/kbn_ts_projects.mdx index a7e5943c97c145..7c47c91d5b6e8b 100644 --- a/api_docs/kbn_ts_projects.mdx +++ b/api_docs/kbn_ts_projects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ts-projects title: "@kbn/ts-projects" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ts-projects plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ts-projects'] --- import kbnTsProjectsObj from './kbn_ts_projects.devdocs.json'; diff --git a/api_docs/kbn_typed_react_router_config.mdx b/api_docs/kbn_typed_react_router_config.mdx index 06e067abd4b713..3c679804719173 100644 --- a/api_docs/kbn_typed_react_router_config.mdx +++ b/api_docs/kbn_typed_react_router_config.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-typed-react-router-config title: "@kbn/typed-react-router-config" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/typed-react-router-config plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/typed-react-router-config'] --- import kbnTypedReactRouterConfigObj from './kbn_typed_react_router_config.devdocs.json'; diff --git a/api_docs/kbn_ui_actions_browser.mdx b/api_docs/kbn_ui_actions_browser.mdx index db44b8d1d9b77b..ded4a31e471206 100644 --- a/api_docs/kbn_ui_actions_browser.mdx +++ b/api_docs/kbn_ui_actions_browser.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-actions-browser title: "@kbn/ui-actions-browser" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-actions-browser plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-actions-browser'] --- import kbnUiActionsBrowserObj from './kbn_ui_actions_browser.devdocs.json'; diff --git a/api_docs/kbn_ui_shared_deps_src.mdx b/api_docs/kbn_ui_shared_deps_src.mdx index 9de86bc88ecd3e..348cd234ac11a4 100644 --- a/api_docs/kbn_ui_shared_deps_src.mdx +++ b/api_docs/kbn_ui_shared_deps_src.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-shared-deps-src title: "@kbn/ui-shared-deps-src" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-shared-deps-src plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-shared-deps-src'] --- import kbnUiSharedDepsSrcObj from './kbn_ui_shared_deps_src.devdocs.json'; diff --git a/api_docs/kbn_ui_theme.mdx b/api_docs/kbn_ui_theme.mdx index 7ef5db807c967c..c6fd0e88c1bd41 100644 --- a/api_docs/kbn_ui_theme.mdx +++ b/api_docs/kbn_ui_theme.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-ui-theme title: "@kbn/ui-theme" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/ui-theme plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/ui-theme'] --- import kbnUiThemeObj from './kbn_ui_theme.devdocs.json'; diff --git a/api_docs/kbn_unified_data_table.mdx b/api_docs/kbn_unified_data_table.mdx index 6acde12d5c61ce..a75933822d3d72 100644 --- a/api_docs/kbn_unified_data_table.mdx +++ b/api_docs/kbn_unified_data_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-data-table title: "@kbn/unified-data-table" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-data-table plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-data-table'] --- import kbnUnifiedDataTableObj from './kbn_unified_data_table.devdocs.json'; diff --git a/api_docs/kbn_unified_doc_viewer.mdx b/api_docs/kbn_unified_doc_viewer.mdx index a3273c62d460c3..4ed57a36a08846 100644 --- a/api_docs/kbn_unified_doc_viewer.mdx +++ b/api_docs/kbn_unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-doc-viewer title: "@kbn/unified-doc-viewer" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-doc-viewer plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-doc-viewer'] --- import kbnUnifiedDocViewerObj from './kbn_unified_doc_viewer.devdocs.json'; diff --git a/api_docs/kbn_unified_field_list.mdx b/api_docs/kbn_unified_field_list.mdx index 99f78e2acfc70c..b358d8011871af 100644 --- a/api_docs/kbn_unified_field_list.mdx +++ b/api_docs/kbn_unified_field_list.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-unified-field-list title: "@kbn/unified-field-list" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/unified-field-list plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/unified-field-list'] --- import kbnUnifiedFieldListObj from './kbn_unified_field_list.devdocs.json'; diff --git a/api_docs/kbn_url_state.mdx b/api_docs/kbn_url_state.mdx index 5c2384b9b3af56..e94c27954961dd 100644 --- a/api_docs/kbn_url_state.mdx +++ b/api_docs/kbn_url_state.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-url-state title: "@kbn/url-state" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/url-state plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/url-state'] --- import kbnUrlStateObj from './kbn_url_state.devdocs.json'; diff --git a/api_docs/kbn_use_tracked_promise.mdx b/api_docs/kbn_use_tracked_promise.mdx index 29010b66ab584c..30f803854956d0 100644 --- a/api_docs/kbn_use_tracked_promise.mdx +++ b/api_docs/kbn_use_tracked_promise.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-use-tracked-promise title: "@kbn/use-tracked-promise" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/use-tracked-promise plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/use-tracked-promise'] --- import kbnUseTrackedPromiseObj from './kbn_use_tracked_promise.devdocs.json'; diff --git a/api_docs/kbn_user_profile_components.mdx b/api_docs/kbn_user_profile_components.mdx index 2e397fa5ef8aa9..3e448ab79c546a 100644 --- a/api_docs/kbn_user_profile_components.mdx +++ b/api_docs/kbn_user_profile_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-user-profile-components title: "@kbn/user-profile-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/user-profile-components plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/user-profile-components'] --- import kbnUserProfileComponentsObj from './kbn_user_profile_components.devdocs.json'; diff --git a/api_docs/kbn_utility_types.mdx b/api_docs/kbn_utility_types.mdx index b41f5d40d05814..3b10ade8b6f3fe 100644 --- a/api_docs/kbn_utility_types.mdx +++ b/api_docs/kbn_utility_types.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types title: "@kbn/utility-types" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types'] --- import kbnUtilityTypesObj from './kbn_utility_types.devdocs.json'; diff --git a/api_docs/kbn_utility_types_jest.mdx b/api_docs/kbn_utility_types_jest.mdx index 36214775c1329b..f23dfad960dc96 100644 --- a/api_docs/kbn_utility_types_jest.mdx +++ b/api_docs/kbn_utility_types_jest.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utility-types-jest title: "@kbn/utility-types-jest" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utility-types-jest plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utility-types-jest'] --- import kbnUtilityTypesJestObj from './kbn_utility_types_jest.devdocs.json'; diff --git a/api_docs/kbn_utils.mdx b/api_docs/kbn_utils.mdx index 1652a49c6e783c..678c6c2a6b3346 100644 --- a/api_docs/kbn_utils.mdx +++ b/api_docs/kbn_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-utils title: "@kbn/utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/utils'] --- import kbnUtilsObj from './kbn_utils.devdocs.json'; diff --git a/api_docs/kbn_visualization_ui_components.mdx b/api_docs/kbn_visualization_ui_components.mdx index 536c7b0e03e0a2..c7ef7a7443fb05 100644 --- a/api_docs/kbn_visualization_ui_components.mdx +++ b/api_docs/kbn_visualization_ui_components.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-visualization-ui-components title: "@kbn/visualization-ui-components" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/visualization-ui-components plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/visualization-ui-components'] --- import kbnVisualizationUiComponentsObj from './kbn_visualization_ui_components.devdocs.json'; diff --git a/api_docs/kbn_xstate_utils.mdx b/api_docs/kbn_xstate_utils.mdx index 7759db9f3b0345..c7b00e2d0d1513 100644 --- a/api_docs/kbn_xstate_utils.mdx +++ b/api_docs/kbn_xstate_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-xstate-utils title: "@kbn/xstate-utils" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/xstate-utils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/xstate-utils'] --- import kbnXstateUtilsObj from './kbn_xstate_utils.devdocs.json'; diff --git a/api_docs/kbn_yarn_lock_validator.mdx b/api_docs/kbn_yarn_lock_validator.mdx index 858fdfbdadc4e6..98c7619b399089 100644 --- a/api_docs/kbn_yarn_lock_validator.mdx +++ b/api_docs/kbn_yarn_lock_validator.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kbn-yarn-lock-validator title: "@kbn/yarn-lock-validator" image: https://source.unsplash.com/400x175/?github description: API docs for the @kbn/yarn-lock-validator plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/yarn-lock-validator'] --- import kbnYarnLockValidatorObj from './kbn_yarn_lock_validator.devdocs.json'; diff --git a/api_docs/kbn_zod_helpers.devdocs.json b/api_docs/kbn_zod_helpers.devdocs.json new file mode 100644 index 00000000000000..aea5a227f726a3 --- /dev/null +++ b/api_docs/kbn_zod_helpers.devdocs.json @@ -0,0 +1,242 @@ +{ + "id": "@kbn/zod-helpers", + "client": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "server": { + "classes": [], + "functions": [], + "interfaces": [], + "enums": [], + "misc": [], + "objects": [] + }, + "common": { + "classes": [], + "functions": [ + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.expectParseError", + "type": "Function", + "tags": [], + "label": "expectParseError", + "description": [], + "signature": [ + "(result: Zod.SafeParseReturnType) => void" + ], + "path": "packages/kbn-zod-helpers/src/expect_parse_error.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.expectParseError.$1", + "type": "CompoundType", + "tags": [], + "label": "result", + "description": [], + "signature": [ + "Zod.SafeParseReturnType" + ], + "path": "packages/kbn-zod-helpers/src/expect_parse_error.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.expectParseSuccess", + "type": "Function", + "tags": [], + "label": "expectParseSuccess", + "description": [], + "signature": [ + "(result: Zod.SafeParseReturnType) => void" + ], + "path": "packages/kbn-zod-helpers/src/expect_parse_success.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.expectParseSuccess.$1", + "type": "CompoundType", + "tags": [], + "label": "result", + "description": [], + "signature": [ + "Zod.SafeParseReturnType" + ], + "path": "packages/kbn-zod-helpers/src/expect_parse_success.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.isValidDateMath", + "type": "Function", + "tags": [], + "label": "isValidDateMath", + "description": [], + "signature": [ + "(input: string, ctx: Zod.RefinementCtx) => void" + ], + "path": "packages/kbn-zod-helpers/src/is_valid_date_math.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.isValidDateMath.$1", + "type": "string", + "tags": [], + "label": "input", + "description": [], + "signature": [ + "string" + ], + "path": "packages/kbn-zod-helpers/src/is_valid_date_math.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + }, + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.isValidDateMath.$2", + "type": "Object", + "tags": [], + "label": "ctx", + "description": [], + "signature": [ + "Zod.RefinementCtx" + ], + "path": "packages/kbn-zod-helpers/src/is_valid_date_math.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.requiredOptional", + "type": "Function", + "tags": [], + "label": "requiredOptional", + "description": [ + "\nThis helper designed to be used with `z.transform` to make all optional fields required.\n" + ], + "signature": [ + "(schema: T) => ", + { + "pluginId": "@kbn/zod-helpers", + "scope": "common", + "docId": "kibKbnZodHelpersPluginApi", + "section": "def-common.RequiredOptional", + "text": "RequiredOptional" + }, + "" + ], + "path": "packages/kbn-zod-helpers/src/required_optional.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.requiredOptional.$1", + "type": "Uncategorized", + "tags": [], + "label": "schema", + "description": [ + "Zod schema" + ], + "signature": [ + "T" + ], + "path": "packages/kbn-zod-helpers/src/required_optional.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [ + "The same schema but with all optional fields required." + ], + "initialIsOpen": false + }, + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.stringifyZodError", + "type": "Function", + "tags": [], + "label": "stringifyZodError", + "description": [], + "signature": [ + "(err: Zod.ZodError) => string" + ], + "path": "packages/kbn-zod-helpers/src/stringify_zod_error.ts", + "deprecated": false, + "trackAdoption": false, + "children": [ + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.stringifyZodError.$1", + "type": "Object", + "tags": [], + "label": "err", + "description": [], + "signature": [ + "Zod.ZodError" + ], + "path": "packages/kbn-zod-helpers/src/stringify_zod_error.ts", + "deprecated": false, + "trackAdoption": false, + "isRequired": true + } + ], + "returnComment": [], + "initialIsOpen": false + } + ], + "interfaces": [], + "enums": [], + "misc": [ + { + "parentPluginId": "@kbn/zod-helpers", + "id": "def-common.RequiredOptional", + "type": "Type", + "tags": [ + "note" + ], + "label": "RequiredOptional", + "description": [ + "\nMake any optional fields required, but add `| undefined` to their type.\n\nThis bit of logic is to force all fields to be accounted for in conversions\nfrom the internal rule schema to the response schema. Rather than use\npartial, which makes each field optional, we make each field required but\npossibly undefined. The result is that if a field is forgotten in the\nconversion from internal schema to response schema TS will report an error.\nIf we just used partial instead, then optional fields can be accidentally\nomitted from the conversion - and any actual values in those fields\ninternally will be stripped in the response.\n" + ], + "signature": [ + "{ [K in keyof T]-?: [T[K]]; } extends infer U ? U extends Record ? { [K in keyof U]: U[K][0]; } : never : never" + ], + "path": "packages/kbn-zod-helpers/src/required_optional.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false + } + ], + "objects": [] + } +} \ No newline at end of file diff --git a/api_docs/kbn_zod_helpers.mdx b/api_docs/kbn_zod_helpers.mdx new file mode 100644 index 00000000000000..4a99cf95d37bf1 --- /dev/null +++ b/api_docs/kbn_zod_helpers.mdx @@ -0,0 +1,33 @@ +--- +#### +#### This document is auto-generated and is meant to be viewed inside our experimental, new docs system. +#### Reach out in #docs-engineering for more info. +#### +id: kibKbnZodHelpersPluginApi +slug: /kibana-dev-docs/api/kbn-zod-helpers +title: "@kbn/zod-helpers" +image: https://source.unsplash.com/400x175/?github +description: API docs for the @kbn/zod-helpers plugin +date: 2023-10-29 +tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/zod-helpers'] +--- +import kbnZodHelpersObj from './kbn_zod_helpers.devdocs.json'; + + + +Contact [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) for questions regarding this plugin. + +**Code health stats** + +| Public API count | Any count | Items lacking comments | Missing exports | +|-------------------|-----------|------------------------|-----------------| +| 12 | 0 | 9 | 0 | + +## Common + +### Functions + + +### Consts, variables and types + + diff --git a/api_docs/kibana_overview.mdx b/api_docs/kibana_overview.mdx index 2eb1379b0527d9..a96b30e794bde0 100644 --- a/api_docs/kibana_overview.mdx +++ b/api_docs/kibana_overview.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaOverview title: "kibanaOverview" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaOverview plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaOverview'] --- import kibanaOverviewObj from './kibana_overview.devdocs.json'; diff --git a/api_docs/kibana_react.mdx b/api_docs/kibana_react.mdx index 500374e2f2dad1..91ce773919f2e2 100644 --- a/api_docs/kibana_react.mdx +++ b/api_docs/kibana_react.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaReact title: "kibanaReact" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaReact plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaReact'] --- import kibanaReactObj from './kibana_react.devdocs.json'; diff --git a/api_docs/kibana_utils.mdx b/api_docs/kibana_utils.mdx index d83bc4ce05838f..5905c5d30509c6 100644 --- a/api_docs/kibana_utils.mdx +++ b/api_docs/kibana_utils.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kibanaUtils title: "kibanaUtils" image: https://source.unsplash.com/400x175/?github description: API docs for the kibanaUtils plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kibanaUtils'] --- import kibanaUtilsObj from './kibana_utils.devdocs.json'; diff --git a/api_docs/kubernetes_security.mdx b/api_docs/kubernetes_security.mdx index 7cbc1f489d8c13..13cb8b6287d723 100644 --- a/api_docs/kubernetes_security.mdx +++ b/api_docs/kubernetes_security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/kubernetesSecurity title: "kubernetesSecurity" image: https://source.unsplash.com/400x175/?github description: API docs for the kubernetesSecurity plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'kubernetesSecurity'] --- import kubernetesSecurityObj from './kubernetes_security.devdocs.json'; diff --git a/api_docs/lens.mdx b/api_docs/lens.mdx index 8431397c657568..02da617ee42e13 100644 --- a/api_docs/lens.mdx +++ b/api_docs/lens.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lens title: "lens" image: https://source.unsplash.com/400x175/?github description: API docs for the lens plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lens'] --- import lensObj from './lens.devdocs.json'; diff --git a/api_docs/license_api_guard.mdx b/api_docs/license_api_guard.mdx index f00059c794c408..c750a95be364db 100644 --- a/api_docs/license_api_guard.mdx +++ b/api_docs/license_api_guard.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseApiGuard title: "licenseApiGuard" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseApiGuard plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseApiGuard'] --- import licenseApiGuardObj from './license_api_guard.devdocs.json'; diff --git a/api_docs/license_management.mdx b/api_docs/license_management.mdx index 4bf25f3da3b0b1..bfa5cb2f3a4879 100644 --- a/api_docs/license_management.mdx +++ b/api_docs/license_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licenseManagement title: "licenseManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the licenseManagement plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licenseManagement'] --- import licenseManagementObj from './license_management.devdocs.json'; diff --git a/api_docs/licensing.mdx b/api_docs/licensing.mdx index d37c56b8a03272..bc03de158c458e 100644 --- a/api_docs/licensing.mdx +++ b/api_docs/licensing.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/licensing title: "licensing" image: https://source.unsplash.com/400x175/?github description: API docs for the licensing plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'licensing'] --- import licensingObj from './licensing.devdocs.json'; diff --git a/api_docs/links.mdx b/api_docs/links.mdx index eff65a560f5e85..4221a55179dd51 100644 --- a/api_docs/links.mdx +++ b/api_docs/links.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/links title: "links" image: https://source.unsplash.com/400x175/?github description: API docs for the links plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'links'] --- import linksObj from './links.devdocs.json'; diff --git a/api_docs/lists.mdx b/api_docs/lists.mdx index 55b442c0aad1de..4181824a8b782e 100644 --- a/api_docs/lists.mdx +++ b/api_docs/lists.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/lists title: "lists" image: https://source.unsplash.com/400x175/?github description: API docs for the lists plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'lists'] --- import listsObj from './lists.devdocs.json'; diff --git a/api_docs/log_explorer.mdx b/api_docs/log_explorer.mdx index 11beabe6a5980e..292fd9a291a91e 100644 --- a/api_docs/log_explorer.mdx +++ b/api_docs/log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logExplorer title: "logExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the logExplorer plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logExplorer'] --- import logExplorerObj from './log_explorer.devdocs.json'; diff --git a/api_docs/logs_shared.mdx b/api_docs/logs_shared.mdx index 2161aadc97fab7..be2beba74a668a 100644 --- a/api_docs/logs_shared.mdx +++ b/api_docs/logs_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/logsShared title: "logsShared" image: https://source.unsplash.com/400x175/?github description: API docs for the logsShared plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'logsShared'] --- import logsSharedObj from './logs_shared.devdocs.json'; diff --git a/api_docs/management.mdx b/api_docs/management.mdx index 45154bf353b5c5..9c333ece15a4ea 100644 --- a/api_docs/management.mdx +++ b/api_docs/management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/management title: "management" image: https://source.unsplash.com/400x175/?github description: API docs for the management plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'management'] --- import managementObj from './management.devdocs.json'; diff --git a/api_docs/maps.mdx b/api_docs/maps.mdx index 45a27b989c7f65..b67fb6b74ddbeb 100644 --- a/api_docs/maps.mdx +++ b/api_docs/maps.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/maps title: "maps" image: https://source.unsplash.com/400x175/?github description: API docs for the maps plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'maps'] --- import mapsObj from './maps.devdocs.json'; diff --git a/api_docs/maps_ems.mdx b/api_docs/maps_ems.mdx index 0a0fa318a979d4..40a3bcd9f5cc0e 100644 --- a/api_docs/maps_ems.mdx +++ b/api_docs/maps_ems.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/mapsEms title: "mapsEms" image: https://source.unsplash.com/400x175/?github description: API docs for the mapsEms plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'mapsEms'] --- import mapsEmsObj from './maps_ems.devdocs.json'; diff --git a/api_docs/metrics_data_access.mdx b/api_docs/metrics_data_access.mdx index e7def5072303c9..add87bae7404ac 100644 --- a/api_docs/metrics_data_access.mdx +++ b/api_docs/metrics_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/metricsDataAccess title: "metricsDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the metricsDataAccess plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.devdocs.json b/api_docs/ml.devdocs.json index a3f795bac57afc..f3254ea9f45524 100644 --- a/api_docs/ml.devdocs.json +++ b/api_docs/ml.devdocs.json @@ -1803,11 +1803,11 @@ "label": "Modules", "description": [], "signature": [ - "{ recognize: (indexPattern: string) => Promise<", + "{ recognize: (indexPattern: string, moduleTagFilters?: string[] | undefined) => Promise<", "RecognizeResult", - "[]>; getModule: (id: string, prefix?: string) => Promise<", + "[]>; getModule: (id: string, moduleTagFilters?: string[] | undefined, prefix?: string) => Promise<", "Module", - ">; listModules: () => Promise<", + ">; listModules: (moduleTagFilters?: string[] | undefined) => Promise<", "Module", "[]>; setup(payload: ", "ModuleSetupPayload", diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 701b3d9fb3c6da..12986ba1985dd2 100644 --- a/api_docs/ml.mdx +++ b/api_docs/ml.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ml title: "ml" image: https://source.unsplash.com/400x175/?github description: API docs for the ml plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ml'] --- import mlObj from './ml.devdocs.json'; diff --git a/api_docs/monitoring.mdx b/api_docs/monitoring.mdx index c0be765292b5ee..ece7e68179b588 100644 --- a/api_docs/monitoring.mdx +++ b/api_docs/monitoring.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoring title: "monitoring" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoring plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoring'] --- import monitoringObj from './monitoring.devdocs.json'; diff --git a/api_docs/monitoring_collection.mdx b/api_docs/monitoring_collection.mdx index 9831dabc862ad5..da4f4b2b51f2a4 100644 --- a/api_docs/monitoring_collection.mdx +++ b/api_docs/monitoring_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/monitoringCollection title: "monitoringCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the monitoringCollection plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'monitoringCollection'] --- import monitoringCollectionObj from './monitoring_collection.devdocs.json'; diff --git a/api_docs/navigation.mdx b/api_docs/navigation.mdx index c7e59f646f580b..8185b4106cd632 100644 --- a/api_docs/navigation.mdx +++ b/api_docs/navigation.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/navigation title: "navigation" image: https://source.unsplash.com/400x175/?github description: API docs for the navigation plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'navigation'] --- import navigationObj from './navigation.devdocs.json'; diff --git a/api_docs/newsfeed.mdx b/api_docs/newsfeed.mdx index a2f3c922d8a07c..6b48e13893de91 100644 --- a/api_docs/newsfeed.mdx +++ b/api_docs/newsfeed.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/newsfeed title: "newsfeed" image: https://source.unsplash.com/400x175/?github description: API docs for the newsfeed plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'newsfeed'] --- import newsfeedObj from './newsfeed.devdocs.json'; diff --git a/api_docs/no_data_page.mdx b/api_docs/no_data_page.mdx index 9ab7dac025b1ea..43da3eb311dfbb 100644 --- a/api_docs/no_data_page.mdx +++ b/api_docs/no_data_page.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/noDataPage title: "noDataPage" image: https://source.unsplash.com/400x175/?github description: API docs for the noDataPage plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'noDataPage'] --- import noDataPageObj from './no_data_page.devdocs.json'; diff --git a/api_docs/notifications.mdx b/api_docs/notifications.mdx index 57d10ac1bbfdef..d3009774bec55d 100644 --- a/api_docs/notifications.mdx +++ b/api_docs/notifications.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/notifications title: "notifications" image: https://source.unsplash.com/400x175/?github description: API docs for the notifications plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'notifications'] --- import notificationsObj from './notifications.devdocs.json'; diff --git a/api_docs/observability.mdx b/api_docs/observability.mdx index c6e8728b472bb0..1e779c1c3074bd 100644 --- a/api_docs/observability.mdx +++ b/api_docs/observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observability title: "observability" image: https://source.unsplash.com/400x175/?github description: API docs for the observability plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observability'] --- import observabilityObj from './observability.devdocs.json'; diff --git a/api_docs/observability_a_i_assistant.mdx b/api_docs/observability_a_i_assistant.mdx index fde3c331594aa2..805e1bafe52d7f 100644 --- a/api_docs/observability_a_i_assistant.mdx +++ b/api_docs/observability_a_i_assistant.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityAIAssistant title: "observabilityAIAssistant" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityAIAssistant plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityAIAssistant'] --- import observabilityAIAssistantObj from './observability_a_i_assistant.devdocs.json'; diff --git a/api_docs/observability_log_explorer.mdx b/api_docs/observability_log_explorer.mdx index e8a300b51543db..567a3451be6ac2 100644 --- a/api_docs/observability_log_explorer.mdx +++ b/api_docs/observability_log_explorer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityLogExplorer title: "observabilityLogExplorer" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityLogExplorer plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityLogExplorer'] --- import observabilityLogExplorerObj from './observability_log_explorer.devdocs.json'; diff --git a/api_docs/observability_onboarding.mdx b/api_docs/observability_onboarding.mdx index a041ec39cb2492..1c82c6e350e214 100644 --- a/api_docs/observability_onboarding.mdx +++ b/api_docs/observability_onboarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityOnboarding title: "observabilityOnboarding" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityOnboarding plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityOnboarding'] --- import observabilityOnboardingObj from './observability_onboarding.devdocs.json'; diff --git a/api_docs/observability_shared.mdx b/api_docs/observability_shared.mdx index 98646b65c8f140..efc8e50e5a532e 100644 --- a/api_docs/observability_shared.mdx +++ b/api_docs/observability_shared.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/observabilityShared title: "observabilityShared" image: https://source.unsplash.com/400x175/?github description: API docs for the observabilityShared plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'observabilityShared'] --- import observabilitySharedObj from './observability_shared.devdocs.json'; diff --git a/api_docs/osquery.mdx b/api_docs/osquery.mdx index 656e01af7c1c3b..d6e40e876b6936 100644 --- a/api_docs/osquery.mdx +++ b/api_docs/osquery.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/osquery title: "osquery" image: https://source.unsplash.com/400x175/?github description: API docs for the osquery plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'osquery'] --- import osqueryObj from './osquery.devdocs.json'; diff --git a/api_docs/painless_lab.mdx b/api_docs/painless_lab.mdx index e9f9222995c595..2271dc0590d603 100644 --- a/api_docs/painless_lab.mdx +++ b/api_docs/painless_lab.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/painlessLab title: "painlessLab" image: https://source.unsplash.com/400x175/?github description: API docs for the painlessLab plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'painlessLab'] --- import painlessLabObj from './painless_lab.devdocs.json'; diff --git a/api_docs/plugin_directory.mdx b/api_docs/plugin_directory.mdx index b73c9234ba2a94..351bae4596fa16 100644 --- a/api_docs/plugin_directory.mdx +++ b/api_docs/plugin_directory.mdx @@ -7,7 +7,7 @@ id: kibDevDocsPluginDirectory slug: /kibana-dev-docs/api-meta/plugin-api-directory title: Directory description: Directory of public APIs available through plugins or packages. -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- @@ -15,13 +15,13 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | Count | Plugins or Packages with a
public API | Number of teams | |--------------|----------|------------------------| -| 703 | 593 | 40 | +| 704 | 594 | 41 | ### Public API health stats | API Count | Any Count | Missing comments | Missing exports | |--------------|----------|-----------------|--------| -| 75914 | 224 | 64915 | 1593 | +| 75925 | 223 | 64928 | 1593 | ## Plugin Directory @@ -56,14 +56,14 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/fleet](https://github.com/orgs/elastic/teams/fleet) | Add custom data integrations so they can be displayed in the Fleet integrations app | 268 | 0 | 249 | 1 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | Adds the Dashboard app to Kibana | 109 | 0 | 106 | 11 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | - | 54 | 0 | 51 | 0 | -| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3186 | 33 | 2537 | 22 | +| | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 3186 | 32 | 2537 | 22 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin provides the ability to create data views via a modal flyout inside Kibana apps | 35 | 0 | 25 | 5 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Reusable data view field editor across Kibana | 72 | 0 | 33 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data view management app | 2 | 0 | 2 | 0 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | Data services are useful for searching and querying data from Elasticsearch. Helpful utilities include: a re-usable react query bar, KQL autocomplete, async search, Data Views (Index Patterns) and field formatters. | 918 | 0 | 255 | 4 | | | [@elastic/ml-ui](https://github.com/orgs/elastic/teams/ml-ui) | The Data Visualizer tools help you understand your data, by analyzing the metrics and fields in a log file or an existing Elasticsearch index. | 31 | 3 | 25 | 1 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 12 | 0 | 10 | 3 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 119 | 0 | 76 | 18 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | This plugin contains the Discover application and the saved search embeddable. | 120 | 0 | 77 | 19 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 35 | 2 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | APIs used to assess the quality of data in Elasticsearch indexes | 2 | 0 | 0 | 0 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Server APIs for the Elastic AI Assistant | 4 | 0 | 2 | 0 | @@ -146,7 +146,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 2 | 0 | 2 | 0 | | | [@elastic/kibana-presentation](https://github.com/orgs/elastic/teams/kibana-presentation) | The Presentation Utility Plugin is a set of common, shared components and toolkits for solutions within the Presentation space, (e.g. Dashboards, Canvas). | 219 | 2 | 164 | 11 | | | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 16 | 1 | 16 | 0 | -| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 24 | 0 | 24 | 7 | +| | [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling-ui) | - | 22 | 0 | 22 | 7 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 23 | 0 | 23 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Reporting Services enables applications to feature reports that the user can automate with Watcher and download later. | 42 | 0 | 22 | 5 | | | [@elastic/platform-deployment-management](https://github.com/orgs/elastic/teams/platform-deployment-management) | - | 21 | 0 | 21 | 0 | @@ -164,7 +164,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-security](https://github.com/orgs/elastic/teams/kibana-security) | This plugin provides authentication and authorization features, and exposes functionality to understand the capabilities of the currently authenticated user. | 270 | 0 | 87 | 3 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | - | 173 | 0 | 106 | 35 | | | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | ESS customizations for Security Solution. | 6 | 0 | 6 | 0 | -| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Serverless customizations for security. | 6 | 0 | 6 | 0 | +| | [@elastic/security-solution](https://github.com/orgs/elastic/teams/security-solution) | Serverless customizations for security. | 7 | 0 | 7 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | The core Serverless plugin, providing APIs to Serverless Project plugins. | 19 | 0 | 18 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | Serverless customizations for observability. | 6 | 0 | 6 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | Serverless customizations for search. | 6 | 0 | 6 | 0 | @@ -452,7 +452,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 52 | 0 | 52 | 1 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 36 | 0 | 14 | 3 | | | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 20 | 0 | 16 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 36 | 0 | 28 | 1 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 37 | 0 | 29 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 2 | 0 | 0 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 29 | 0 | 29 | 1 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 1 | 0 | 0 | 0 | @@ -521,7 +521,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 55 | 1 | 50 | 0 | | | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 13 | 0 | 13 | 3 | | | [@elastic/actionable-observability](https://github.com/orgs/elastic/teams/actionable-observability) | - | 99 | 1 | 99 | 0 | -| | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 7 | 0 | 7 | 0 | +| | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 7 | 0 | 7 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 45 | 0 | 45 | 10 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 51 | 5 | 34 | 0 | | | [@elastic/security-asset-management](https://github.com/orgs/elastic/teams/security-asset-management) | - | 62 | 0 | 62 | 0 | @@ -549,7 +549,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 68 | 0 | 68 | 0 | | | [@elastic/enterprise-search-frontend](https://github.com/orgs/elastic/teams/enterprise-search-frontend) | - | 2211 | 0 | 2211 | 0 | -| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 14 | 0 | 7 | 2 | +| | [@elastic/kibana-data-discovery](https://github.com/orgs/elastic/teams/kibana-data-discovery) | - | 14 | 0 | 12 | 1 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 14 | 0 | 14 | 6 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 52 | 0 | 48 | 0 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 29 | 0 | 23 | 0 | @@ -557,7 +557,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 56 | 1 | 41 | 1 | | | [@elastic/security-threat-hunting-investigations](https://github.com/orgs/elastic/teams/security-threat-hunting-investigations) | - | 95 | 0 | 72 | 7 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 341 | 1 | 337 | 32 | -| | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 89 | 0 | 78 | 1 | +| | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 87 | 0 | 76 | 1 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 104 | 0 | 93 | 1 | | | [@elastic/security-threat-hunting-explore](https://github.com/orgs/elastic/teams/security-threat-hunting-explore) | - | 17 | 0 | 12 | 7 | | | [@elastic/security-detection-engine](https://github.com/orgs/elastic/teams/security-detection-engine) | - | 15 | 0 | 7 | 0 | @@ -587,8 +587,8 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 28 | 0 | 10 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 10 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 32 | 0 | 28 | 0 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 60 | 0 | 48 | 4 | -| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 4 | 0 | 1 | 0 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 58 | 0 | 47 | 4 | +| | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 6 | 0 | 2 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 5 | 0 | 4 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 3 | 0 | 2 | 0 | | | [@elastic/appex-sharedux](https://github.com/orgs/elastic/teams/appex-sharedux) | - | 2 | 0 | 2 | 0 | @@ -649,4 +649,5 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@elastic/kibana-visualizations](https://github.com/orgs/elastic/teams/kibana-visualizations) | - | 156 | 0 | 152 | 3 | | | [@elastic/infra-monitoring-ui](https://github.com/orgs/elastic/teams/infra-monitoring-ui) | - | 12 | 0 | 12 | 0 | | | [@elastic/kibana-operations](https://github.com/orgs/elastic/teams/kibana-operations) | - | 6 | 0 | 2 | 0 | +| | [@elastic/security-detection-rule-management](https://github.com/orgs/elastic/teams/security-detection-rule-management) | - | 12 | 0 | 9 | 0 | diff --git a/api_docs/presentation_util.mdx b/api_docs/presentation_util.mdx index ed1e53bcbed3fe..fe46ddf4e0dc29 100644 --- a/api_docs/presentation_util.mdx +++ b/api_docs/presentation_util.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/presentationUtil title: "presentationUtil" image: https://source.unsplash.com/400x175/?github description: API docs for the presentationUtil plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'presentationUtil'] --- import presentationUtilObj from './presentation_util.devdocs.json'; diff --git a/api_docs/profiling.mdx b/api_docs/profiling.mdx index 9eac89979a492b..608cb73401d1c4 100644 --- a/api_docs/profiling.mdx +++ b/api_docs/profiling.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profiling title: "profiling" image: https://source.unsplash.com/400x175/?github description: API docs for the profiling plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profiling'] --- import profilingObj from './profiling.devdocs.json'; diff --git a/api_docs/profiling_data_access.devdocs.json b/api_docs/profiling_data_access.devdocs.json index c44f5d9549d950..0e1b1fab4bee58 100644 --- a/api_docs/profiling_data_access.devdocs.json +++ b/api_docs/profiling_data_access.devdocs.json @@ -493,36 +493,6 @@ "trackAdoption": false, "initialIsOpen": false }, - { - "parentPluginId": "profilingDataAccess", - "id": "def-common.METADATA_VERSION", - "type": "number", - "tags": [], - "label": "METADATA_VERSION", - "description": [], - "signature": [ - "1" - ], - "path": "x-pack/plugins/profiling_data_access/common/security_role.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, - { - "parentPluginId": "profilingDataAccess", - "id": "def-common.PROFILING_READER_ROLE_NAME", - "type": "string", - "tags": [], - "label": "PROFILING_READER_ROLE_NAME", - "description": [], - "signature": [ - "\"profiling-reader\"" - ], - "path": "x-pack/plugins/profiling_data_access/common/security_role.ts", - "deprecated": false, - "trackAdoption": false, - "initialIsOpen": false - }, { "parentPluginId": "profilingDataAccess", "id": "def-common.SYMBOLIZER_PACKAGE_POLICY_NAME", diff --git a/api_docs/profiling_data_access.mdx b/api_docs/profiling_data_access.mdx index d0af0b6f595765..1ad3a3b13a5395 100644 --- a/api_docs/profiling_data_access.mdx +++ b/api_docs/profiling_data_access.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/profilingDataAccess title: "profilingDataAccess" image: https://source.unsplash.com/400x175/?github description: API docs for the profilingDataAccess plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'profilingDataAccess'] --- import profilingDataAccessObj from './profiling_data_access.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/profiling-ui](https://github.com/orgs/elastic/teams/profiling- | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 24 | 0 | 24 | 7 | +| 22 | 0 | 22 | 7 | ## Server diff --git a/api_docs/remote_clusters.mdx b/api_docs/remote_clusters.mdx index a8b40f82634515..bd6e2e421db5a0 100644 --- a/api_docs/remote_clusters.mdx +++ b/api_docs/remote_clusters.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/remoteClusters title: "remoteClusters" image: https://source.unsplash.com/400x175/?github description: API docs for the remoteClusters plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'remoteClusters'] --- import remoteClustersObj from './remote_clusters.devdocs.json'; diff --git a/api_docs/reporting.mdx b/api_docs/reporting.mdx index e89c27d0f78400..113b883b658037 100644 --- a/api_docs/reporting.mdx +++ b/api_docs/reporting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/reporting title: "reporting" image: https://source.unsplash.com/400x175/?github description: API docs for the reporting plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'reporting'] --- import reportingObj from './reporting.devdocs.json'; diff --git a/api_docs/rollup.mdx b/api_docs/rollup.mdx index f1aa66e48281a0..81ac6b4eb32a46 100644 --- a/api_docs/rollup.mdx +++ b/api_docs/rollup.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/rollup title: "rollup" image: https://source.unsplash.com/400x175/?github description: API docs for the rollup plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'rollup'] --- import rollupObj from './rollup.devdocs.json'; diff --git a/api_docs/rule_registry.mdx b/api_docs/rule_registry.mdx index c6d5a7351c7c55..8fc7a111189147 100644 --- a/api_docs/rule_registry.mdx +++ b/api_docs/rule_registry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ruleRegistry title: "ruleRegistry" image: https://source.unsplash.com/400x175/?github description: API docs for the ruleRegistry plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ruleRegistry'] --- import ruleRegistryObj from './rule_registry.devdocs.json'; diff --git a/api_docs/runtime_fields.mdx b/api_docs/runtime_fields.mdx index 7d816f55fa212d..0efadd4383aae6 100644 --- a/api_docs/runtime_fields.mdx +++ b/api_docs/runtime_fields.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/runtimeFields title: "runtimeFields" image: https://source.unsplash.com/400x175/?github description: API docs for the runtimeFields plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'runtimeFields'] --- import runtimeFieldsObj from './runtime_fields.devdocs.json'; diff --git a/api_docs/saved_objects.mdx b/api_docs/saved_objects.mdx index 99df4a83c1bba1..9734e8aa7e81ec 100644 --- a/api_docs/saved_objects.mdx +++ b/api_docs/saved_objects.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjects title: "savedObjects" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjects plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjects'] --- import savedObjectsObj from './saved_objects.devdocs.json'; diff --git a/api_docs/saved_objects_finder.mdx b/api_docs/saved_objects_finder.mdx index 7ae16748c84ba5..0d8c6aba3a57c5 100644 --- a/api_docs/saved_objects_finder.mdx +++ b/api_docs/saved_objects_finder.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsFinder title: "savedObjectsFinder" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsFinder plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsFinder'] --- import savedObjectsFinderObj from './saved_objects_finder.devdocs.json'; diff --git a/api_docs/saved_objects_management.mdx b/api_docs/saved_objects_management.mdx index 328e276f94697b..e6e5c6bb273d8a 100644 --- a/api_docs/saved_objects_management.mdx +++ b/api_docs/saved_objects_management.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsManagement title: "savedObjectsManagement" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsManagement plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsManagement'] --- import savedObjectsManagementObj from './saved_objects_management.devdocs.json'; diff --git a/api_docs/saved_objects_tagging.mdx b/api_docs/saved_objects_tagging.mdx index c5a769cc485fa8..f158d218c6500f 100644 --- a/api_docs/saved_objects_tagging.mdx +++ b/api_docs/saved_objects_tagging.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTagging title: "savedObjectsTagging" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTagging plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTagging'] --- import savedObjectsTaggingObj from './saved_objects_tagging.devdocs.json'; diff --git a/api_docs/saved_objects_tagging_oss.mdx b/api_docs/saved_objects_tagging_oss.mdx index 3fec562d534790..e80327802499f9 100644 --- a/api_docs/saved_objects_tagging_oss.mdx +++ b/api_docs/saved_objects_tagging_oss.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedObjectsTaggingOss title: "savedObjectsTaggingOss" image: https://source.unsplash.com/400x175/?github description: API docs for the savedObjectsTaggingOss plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/saved_search.devdocs.json b/api_docs/saved_search.devdocs.json index 6dda75e6527d01..3945e98295ff17 100644 --- a/api_docs/saved_search.devdocs.json +++ b/api_docs/saved_search.devdocs.json @@ -1208,7 +1208,7 @@ "section": "def-common.SearchSourceSearchOptions", "text": "SearchSourceSearchOptions" }, - " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean, includeFields?: boolean) => ", + " | undefined) => Promise) => void; getSearchRequestBody: () => any; destroy: () => void; getSerializedFields: (recurse?: boolean) => ", { "pluginId": "data", "scope": "common", diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index 37b011078912a8..3ac0c96b5589b1 100644 --- a/api_docs/saved_search.mdx +++ b/api_docs/saved_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/savedSearch title: "savedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the savedSearch plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedSearch'] --- import savedSearchObj from './saved_search.devdocs.json'; diff --git a/api_docs/screenshot_mode.mdx b/api_docs/screenshot_mode.mdx index 6578076e0596c5..3904cfc8f65013 100644 --- a/api_docs/screenshot_mode.mdx +++ b/api_docs/screenshot_mode.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotMode title: "screenshotMode" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotMode plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotMode'] --- import screenshotModeObj from './screenshot_mode.devdocs.json'; diff --git a/api_docs/screenshotting.mdx b/api_docs/screenshotting.mdx index f294b09db7098f..d408bdd152c9df 100644 --- a/api_docs/screenshotting.mdx +++ b/api_docs/screenshotting.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/screenshotting title: "screenshotting" image: https://source.unsplash.com/400x175/?github description: API docs for the screenshotting plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'screenshotting'] --- import screenshottingObj from './screenshotting.devdocs.json'; diff --git a/api_docs/security.mdx b/api_docs/security.mdx index 9e351f68417ceb..db87bd73cd034d 100644 --- a/api_docs/security.mdx +++ b/api_docs/security.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/security title: "security" image: https://source.unsplash.com/400x175/?github description: API docs for the security plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'security'] --- import securityObj from './security.devdocs.json'; diff --git a/api_docs/security_solution.mdx b/api_docs/security_solution.mdx index 49701765f0cff0..8974f53dd0cc89 100644 --- a/api_docs/security_solution.mdx +++ b/api_docs/security_solution.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolution title: "securitySolution" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolution plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolution'] --- import securitySolutionObj from './security_solution.devdocs.json'; diff --git a/api_docs/security_solution_ess.mdx b/api_docs/security_solution_ess.mdx index 52baff9c338b2e..eb6e6b6f6135f7 100644 --- a/api_docs/security_solution_ess.mdx +++ b/api_docs/security_solution_ess.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionEss title: "securitySolutionEss" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionEss plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.devdocs.json b/api_docs/security_solution_serverless.devdocs.json index 39d3db16cf5daf..f216fd2475aca9 100644 --- a/api_docs/security_solution_serverless.devdocs.json +++ b/api_docs/security_solution_serverless.devdocs.json @@ -107,6 +107,21 @@ "deprecated": false, "trackAdoption": false, "initialIsOpen": false + }, + { + "parentPluginId": "securitySolutionServerless", + "id": "def-common.SECURITY_PROJECT_TYPE", + "type": "string", + "tags": [], + "label": "SECURITY_PROJECT_TYPE", + "description": [], + "signature": [ + "\"security\"" + ], + "path": "x-pack/plugins/security_solution_serverless/common/index.ts", + "deprecated": false, + "trackAdoption": false, + "initialIsOpen": false } ], "objects": [] diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index 48c3bbc1886960..75de0ed6ffa354 100644 --- a/api_docs/security_solution_serverless.mdx +++ b/api_docs/security_solution_serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/securitySolutionServerless title: "securitySolutionServerless" image: https://source.unsplash.com/400x175/?github description: API docs for the securitySolutionServerless plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; @@ -21,7 +21,7 @@ Contact [@elastic/security-solution](https://github.com/orgs/elastic/teams/secur | Public API count | Any count | Items lacking comments | Missing exports | |-------------------|-----------|------------------------|-----------------| -| 6 | 0 | 6 | 0 | +| 7 | 0 | 7 | 0 | ## Client diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 26e8965950c8cc..9525a3f8ea6ca1 100644 --- a/api_docs/serverless.mdx +++ b/api_docs/serverless.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverless title: "serverless" image: https://source.unsplash.com/400x175/?github description: API docs for the serverless plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverless'] --- import serverlessObj from './serverless.devdocs.json'; diff --git a/api_docs/serverless_observability.mdx b/api_docs/serverless_observability.mdx index f71e2311bb0452..53c4b515f8fca1 100644 --- a/api_docs/serverless_observability.mdx +++ b/api_docs/serverless_observability.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessObservability title: "serverlessObservability" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessObservability plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessObservability'] --- import serverlessObservabilityObj from './serverless_observability.devdocs.json'; diff --git a/api_docs/serverless_search.mdx b/api_docs/serverless_search.mdx index 66dc9ed2b9fdc6..cb85f4a2925e84 100644 --- a/api_docs/serverless_search.mdx +++ b/api_docs/serverless_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/serverlessSearch title: "serverlessSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the serverlessSearch plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'serverlessSearch'] --- import serverlessSearchObj from './serverless_search.devdocs.json'; diff --git a/api_docs/session_view.mdx b/api_docs/session_view.mdx index 820c83ccb5f6ab..996a9ff475ddb3 100644 --- a/api_docs/session_view.mdx +++ b/api_docs/session_view.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/sessionView title: "sessionView" image: https://source.unsplash.com/400x175/?github description: API docs for the sessionView plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'sessionView'] --- import sessionViewObj from './session_view.devdocs.json'; diff --git a/api_docs/share.mdx b/api_docs/share.mdx index a5dfbf1557cd8c..7c9c0107f250aa 100644 --- a/api_docs/share.mdx +++ b/api_docs/share.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/share title: "share" image: https://source.unsplash.com/400x175/?github description: API docs for the share plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'share'] --- import shareObj from './share.devdocs.json'; diff --git a/api_docs/snapshot_restore.mdx b/api_docs/snapshot_restore.mdx index be7c0f0007028c..1bf715ea443324 100644 --- a/api_docs/snapshot_restore.mdx +++ b/api_docs/snapshot_restore.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/snapshotRestore title: "snapshotRestore" image: https://source.unsplash.com/400x175/?github description: API docs for the snapshotRestore plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'snapshotRestore'] --- import snapshotRestoreObj from './snapshot_restore.devdocs.json'; diff --git a/api_docs/spaces.mdx b/api_docs/spaces.mdx index 063e848846bffb..aa14d2b09ab89d 100644 --- a/api_docs/spaces.mdx +++ b/api_docs/spaces.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/spaces title: "spaces" image: https://source.unsplash.com/400x175/?github description: API docs for the spaces plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'spaces'] --- import spacesObj from './spaces.devdocs.json'; diff --git a/api_docs/stack_alerts.mdx b/api_docs/stack_alerts.mdx index 7db318904fa1b4..5df6b98e1a5ccf 100644 --- a/api_docs/stack_alerts.mdx +++ b/api_docs/stack_alerts.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackAlerts title: "stackAlerts" image: https://source.unsplash.com/400x175/?github description: API docs for the stackAlerts plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackAlerts'] --- import stackAlertsObj from './stack_alerts.devdocs.json'; diff --git a/api_docs/stack_connectors.mdx b/api_docs/stack_connectors.mdx index 38d3b04cb63963..620b1ada6f78b9 100644 --- a/api_docs/stack_connectors.mdx +++ b/api_docs/stack_connectors.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/stackConnectors title: "stackConnectors" image: https://source.unsplash.com/400x175/?github description: API docs for the stackConnectors plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'stackConnectors'] --- import stackConnectorsObj from './stack_connectors.devdocs.json'; diff --git a/api_docs/task_manager.mdx b/api_docs/task_manager.mdx index 47f661e6244e28..e61134e7438b00 100644 --- a/api_docs/task_manager.mdx +++ b/api_docs/task_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/taskManager title: "taskManager" image: https://source.unsplash.com/400x175/?github description: API docs for the taskManager plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'taskManager'] --- import taskManagerObj from './task_manager.devdocs.json'; diff --git a/api_docs/telemetry.mdx b/api_docs/telemetry.mdx index 0f48b95a09c244..578a8f3b7d9f4e 100644 --- a/api_docs/telemetry.mdx +++ b/api_docs/telemetry.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetry title: "telemetry" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetry plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetry'] --- import telemetryObj from './telemetry.devdocs.json'; diff --git a/api_docs/telemetry_collection_manager.mdx b/api_docs/telemetry_collection_manager.mdx index ef8dc107a43e0b..3108c6e4a46932 100644 --- a/api_docs/telemetry_collection_manager.mdx +++ b/api_docs/telemetry_collection_manager.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionManager title: "telemetryCollectionManager" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionManager plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionManager'] --- import telemetryCollectionManagerObj from './telemetry_collection_manager.devdocs.json'; diff --git a/api_docs/telemetry_collection_xpack.mdx b/api_docs/telemetry_collection_xpack.mdx index 3383b8d148016b..025fe8c7945497 100644 --- a/api_docs/telemetry_collection_xpack.mdx +++ b/api_docs/telemetry_collection_xpack.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryCollectionXpack title: "telemetryCollectionXpack" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryCollectionXpack plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryCollectionXpack'] --- import telemetryCollectionXpackObj from './telemetry_collection_xpack.devdocs.json'; diff --git a/api_docs/telemetry_management_section.mdx b/api_docs/telemetry_management_section.mdx index e652c943d46838..8c1fdb68071126 100644 --- a/api_docs/telemetry_management_section.mdx +++ b/api_docs/telemetry_management_section.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/telemetryManagementSection title: "telemetryManagementSection" image: https://source.unsplash.com/400x175/?github description: API docs for the telemetryManagementSection plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'telemetryManagementSection'] --- import telemetryManagementSectionObj from './telemetry_management_section.devdocs.json'; diff --git a/api_docs/text_based_languages.mdx b/api_docs/text_based_languages.mdx index 3b19961fe61673..49f39994fbdb81 100644 --- a/api_docs/text_based_languages.mdx +++ b/api_docs/text_based_languages.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/textBasedLanguages title: "textBasedLanguages" image: https://source.unsplash.com/400x175/?github description: API docs for the textBasedLanguages plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'textBasedLanguages'] --- import textBasedLanguagesObj from './text_based_languages.devdocs.json'; diff --git a/api_docs/threat_intelligence.mdx b/api_docs/threat_intelligence.mdx index 57f7d8e88c82f6..673ab62aecea7f 100644 --- a/api_docs/threat_intelligence.mdx +++ b/api_docs/threat_intelligence.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/threatIntelligence title: "threatIntelligence" image: https://source.unsplash.com/400x175/?github description: API docs for the threatIntelligence plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'threatIntelligence'] --- import threatIntelligenceObj from './threat_intelligence.devdocs.json'; diff --git a/api_docs/timelines.mdx b/api_docs/timelines.mdx index ec27507a071fcf..e32b95d7b6ee6b 100644 --- a/api_docs/timelines.mdx +++ b/api_docs/timelines.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/timelines title: "timelines" image: https://source.unsplash.com/400x175/?github description: API docs for the timelines plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'timelines'] --- import timelinesObj from './timelines.devdocs.json'; diff --git a/api_docs/transform.mdx b/api_docs/transform.mdx index 79996f59a74340..9e111b7b3934b1 100644 --- a/api_docs/transform.mdx +++ b/api_docs/transform.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/transform title: "transform" image: https://source.unsplash.com/400x175/?github description: API docs for the transform plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'transform'] --- import transformObj from './transform.devdocs.json'; diff --git a/api_docs/triggers_actions_ui.mdx b/api_docs/triggers_actions_ui.mdx index 3e54ee6e7f2a2e..50cecdded33504 100644 --- a/api_docs/triggers_actions_ui.mdx +++ b/api_docs/triggers_actions_ui.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/triggersActionsUi title: "triggersActionsUi" image: https://source.unsplash.com/400x175/?github description: API docs for the triggersActionsUi plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'triggersActionsUi'] --- import triggersActionsUiObj from './triggers_actions_ui.devdocs.json'; diff --git a/api_docs/ui_actions.mdx b/api_docs/ui_actions.mdx index f0e1cde23a4487..c8b98104854b59 100644 --- a/api_docs/ui_actions.mdx +++ b/api_docs/ui_actions.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActions title: "uiActions" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActions plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActions'] --- import uiActionsObj from './ui_actions.devdocs.json'; diff --git a/api_docs/ui_actions_enhanced.mdx b/api_docs/ui_actions_enhanced.mdx index eae9c05c9ab6c0..5c5feb1725e15e 100644 --- a/api_docs/ui_actions_enhanced.mdx +++ b/api_docs/ui_actions_enhanced.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uiActionsEnhanced title: "uiActionsEnhanced" image: https://source.unsplash.com/400x175/?github description: API docs for the uiActionsEnhanced plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uiActionsEnhanced'] --- import uiActionsEnhancedObj from './ui_actions_enhanced.devdocs.json'; diff --git a/api_docs/unified_doc_viewer.mdx b/api_docs/unified_doc_viewer.mdx index d4a6fe89976785..1c28a4b612747e 100644 --- a/api_docs/unified_doc_viewer.mdx +++ b/api_docs/unified_doc_viewer.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedDocViewer title: "unifiedDocViewer" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedDocViewer plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedDocViewer'] --- import unifiedDocViewerObj from './unified_doc_viewer.devdocs.json'; diff --git a/api_docs/unified_histogram.mdx b/api_docs/unified_histogram.mdx index e834c649e11770..a76c1a155712c3 100644 --- a/api_docs/unified_histogram.mdx +++ b/api_docs/unified_histogram.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedHistogram title: "unifiedHistogram" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedHistogram plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedHistogram'] --- import unifiedHistogramObj from './unified_histogram.devdocs.json'; diff --git a/api_docs/unified_search.mdx b/api_docs/unified_search.mdx index 81fb594bbc0374..5dc02cf34ce797 100644 --- a/api_docs/unified_search.mdx +++ b/api_docs/unified_search.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch title: "unifiedSearch" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch'] --- import unifiedSearchObj from './unified_search.devdocs.json'; diff --git a/api_docs/unified_search_autocomplete.mdx b/api_docs/unified_search_autocomplete.mdx index 6aa90e06a9dd4a..0d40b6f544c14a 100644 --- a/api_docs/unified_search_autocomplete.mdx +++ b/api_docs/unified_search_autocomplete.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/unifiedSearch-autocomplete title: "unifiedSearch.autocomplete" image: https://source.unsplash.com/400x175/?github description: API docs for the unifiedSearch.autocomplete plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'unifiedSearch.autocomplete'] --- import unifiedSearchAutocompleteObj from './unified_search_autocomplete.devdocs.json'; diff --git a/api_docs/uptime.mdx b/api_docs/uptime.mdx index cc16ccf7328311..d8641cd22a8526 100644 --- a/api_docs/uptime.mdx +++ b/api_docs/uptime.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/uptime title: "uptime" image: https://source.unsplash.com/400x175/?github description: API docs for the uptime plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'uptime'] --- import uptimeObj from './uptime.devdocs.json'; diff --git a/api_docs/url_forwarding.mdx b/api_docs/url_forwarding.mdx index 5f56715db1c8a3..a7551c56eb0d0d 100644 --- a/api_docs/url_forwarding.mdx +++ b/api_docs/url_forwarding.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/urlForwarding title: "urlForwarding" image: https://source.unsplash.com/400x175/?github description: API docs for the urlForwarding plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'urlForwarding'] --- import urlForwardingObj from './url_forwarding.devdocs.json'; diff --git a/api_docs/usage_collection.mdx b/api_docs/usage_collection.mdx index a5d49db0e4f782..b660c86de9e0a5 100644 --- a/api_docs/usage_collection.mdx +++ b/api_docs/usage_collection.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/usageCollection title: "usageCollection" image: https://source.unsplash.com/400x175/?github description: API docs for the usageCollection plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'usageCollection'] --- import usageCollectionObj from './usage_collection.devdocs.json'; diff --git a/api_docs/ux.mdx b/api_docs/ux.mdx index 1ab2bb399f10b4..deaf08bf45458d 100644 --- a/api_docs/ux.mdx +++ b/api_docs/ux.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/ux title: "ux" image: https://source.unsplash.com/400x175/?github description: API docs for the ux plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'ux'] --- import uxObj from './ux.devdocs.json'; diff --git a/api_docs/vis_default_editor.mdx b/api_docs/vis_default_editor.mdx index 5bfad2e3399a3d..996bf48dbd2476 100644 --- a/api_docs/vis_default_editor.mdx +++ b/api_docs/vis_default_editor.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visDefaultEditor title: "visDefaultEditor" image: https://source.unsplash.com/400x175/?github description: API docs for the visDefaultEditor plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visDefaultEditor'] --- import visDefaultEditorObj from './vis_default_editor.devdocs.json'; diff --git a/api_docs/vis_type_gauge.mdx b/api_docs/vis_type_gauge.mdx index 907d97e682ec22..e86cc15657d10d 100644 --- a/api_docs/vis_type_gauge.mdx +++ b/api_docs/vis_type_gauge.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeGauge title: "visTypeGauge" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeGauge plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeGauge'] --- import visTypeGaugeObj from './vis_type_gauge.devdocs.json'; diff --git a/api_docs/vis_type_heatmap.mdx b/api_docs/vis_type_heatmap.mdx index 940022351ab471..25e5af09ece4d5 100644 --- a/api_docs/vis_type_heatmap.mdx +++ b/api_docs/vis_type_heatmap.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeHeatmap title: "visTypeHeatmap" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeHeatmap plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeHeatmap'] --- import visTypeHeatmapObj from './vis_type_heatmap.devdocs.json'; diff --git a/api_docs/vis_type_pie.mdx b/api_docs/vis_type_pie.mdx index ee89a934a32fd0..36af65f527da02 100644 --- a/api_docs/vis_type_pie.mdx +++ b/api_docs/vis_type_pie.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypePie title: "visTypePie" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypePie plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypePie'] --- import visTypePieObj from './vis_type_pie.devdocs.json'; diff --git a/api_docs/vis_type_table.mdx b/api_docs/vis_type_table.mdx index 6a8ed40ee1fe7b..8bae66dff2aed5 100644 --- a/api_docs/vis_type_table.mdx +++ b/api_docs/vis_type_table.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTable title: "visTypeTable" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTable plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTable'] --- import visTypeTableObj from './vis_type_table.devdocs.json'; diff --git a/api_docs/vis_type_timelion.mdx b/api_docs/vis_type_timelion.mdx index df8386931002d8..df2e13189d2cd7 100644 --- a/api_docs/vis_type_timelion.mdx +++ b/api_docs/vis_type_timelion.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimelion title: "visTypeTimelion" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimelion plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimelion'] --- import visTypeTimelionObj from './vis_type_timelion.devdocs.json'; diff --git a/api_docs/vis_type_timeseries.mdx b/api_docs/vis_type_timeseries.mdx index 1118fb10a31b81..d5111750eecbde 100644 --- a/api_docs/vis_type_timeseries.mdx +++ b/api_docs/vis_type_timeseries.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeTimeseries title: "visTypeTimeseries" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeTimeseries plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeTimeseries'] --- import visTypeTimeseriesObj from './vis_type_timeseries.devdocs.json'; diff --git a/api_docs/vis_type_vega.mdx b/api_docs/vis_type_vega.mdx index 09c752f7473140..e2feb425e248e3 100644 --- a/api_docs/vis_type_vega.mdx +++ b/api_docs/vis_type_vega.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVega title: "visTypeVega" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVega plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVega'] --- import visTypeVegaObj from './vis_type_vega.devdocs.json'; diff --git a/api_docs/vis_type_vislib.mdx b/api_docs/vis_type_vislib.mdx index 32742411a83a17..44e87c10dad32a 100644 --- a/api_docs/vis_type_vislib.mdx +++ b/api_docs/vis_type_vislib.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeVislib title: "visTypeVislib" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeVislib plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeVislib'] --- import visTypeVislibObj from './vis_type_vislib.devdocs.json'; diff --git a/api_docs/vis_type_xy.mdx b/api_docs/vis_type_xy.mdx index 0702abb116d63e..84cd7cf2283645 100644 --- a/api_docs/vis_type_xy.mdx +++ b/api_docs/vis_type_xy.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visTypeXy title: "visTypeXy" image: https://source.unsplash.com/400x175/?github description: API docs for the visTypeXy plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visTypeXy'] --- import visTypeXyObj from './vis_type_xy.devdocs.json'; diff --git a/api_docs/visualizations.mdx b/api_docs/visualizations.mdx index f0759dbcd2a5e7..8faed3a5e50df7 100644 --- a/api_docs/visualizations.mdx +++ b/api_docs/visualizations.mdx @@ -8,7 +8,7 @@ slug: /kibana-dev-docs/api/visualizations title: "visualizations" image: https://source.unsplash.com/400x175/?github description: API docs for the visualizations plugin -date: 2023-10-26 +date: 2023-10-29 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'visualizations'] --- import visualizationsObj from './visualizations.devdocs.json'; diff --git a/docs/api/synthetics/params/add-param.asciidoc b/docs/api/synthetics/params/add-param.asciidoc new file mode 100644 index 00000000000000..fa21b5a33738ee --- /dev/null +++ b/docs/api/synthetics/params/add-param.asciidoc @@ -0,0 +1,123 @@ +[[add-parameters-api]] +== Add Parameters API +++++ +Add Parameters +++++ + +Adds one or more parameters to the synthetics app. + +=== {api-request-title} + +`POST :/api/synthetics/params` + +`POST :/s//api/synthetics/params` + +=== {api-prereq-title} + +You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + + +[[parameters-add-request-body]] +==== Request body + +The request body can contain either a single parameter object or an array of parameter objects. The parameter object schema includes the following attributes: + +`key`:: +(Required, string) The key of the parameter. + +`value`:: +(Required, string) The value associated with the parameter. + +`description`:: +(Optional, string) A description of the parameter. + +`tags`:: +(Optional, array of strings) An array of tags to categorize the parameter. + +`share_across_spaces`:: +(Optional, boolean) Whether the parameter should be shared across spaces. + +When adding a single parameter, provide a single object. When adding multiple parameters, provide an array of parameter objects. + +[[parameters-add-example]] +==== Example + +Here are examples of POST requests to add parameters, either as a single parameter or as an array of parameters: + +To add a single parameter: + +[source,sh] +-------------------------------------------------- +POST /api/synthetics/params +{ + "key": "your-key-name", + "value": "your-parameter-value", + "description": "Param to use in browser monitor", + "tags": ["authentication", "security"], + "share_across_spaces": true +} +-------------------------------------------------- + +To add multiple parameters: + +[source,sh] +-------------------------------------------------- +POST /api/synthetics/params +[ + { + "key": "param1", + "value": "value1" + }, + { + "key": "param2", + "value": "value2" + } +] +-------------------------------------------------- + +The API returns a response based on the request. If you added a single parameter, it will return a single parameter object. If you added multiple parameters, it will return an array of parameter objects. + +[[parameters-add-response-example]] +==== Response Example + +The API response includes the created parameter(s) as JSON objects, where each parameter object has the following attributes: + +- `id` (string): The unique identifier of the parameter. +- `key` (string): The key of the parameter. +- `value` (string): The value associated with the parameter. +- `description` (string, optional): The description of the parameter. +- `tags` (array of strings, optional): An array of tags associated with the parameter. +- `share_across_spaces` (boolean, optional): Indicates whether the parameter is shared across spaces. + +Here's an example response for a single added parameter: + +[source,json] +-------------------------------------------------- +{ + "id": "unique-parameter-id", + "key": "your-key-name", + "value": "your-param-value", + "description": "Param to use in browser monitor", + "tags": ["authentication", "security"], + "share_across_spaces": true +} +-------------------------------------------------- + +And here's an example response for adding multiple parameters: + +[source,json] +-------------------------------------------------- +[ + { + "id": "param1-id", + "key": "param1", + "value": "value1" + }, + { + "id": "param2-id", + "key": "param2", + "value": "value2" + } +] +-------------------------------------------------- \ No newline at end of file diff --git a/docs/api/synthetics/params/delete-param.asciidoc b/docs/api/synthetics/params/delete-param.asciidoc new file mode 100644 index 00000000000000..4c7d7911ec180a --- /dev/null +++ b/docs/api/synthetics/params/delete-param.asciidoc @@ -0,0 +1,67 @@ +[[delete-parameters-api]] +== Delete Parameters API +++++ +Delete Parameters +++++ + +Deletes one or more parameters from the Synthetics app. + +=== {api-request-title} + +`DELETE :/api/synthetics/params` + +`DELETE :/s//api/synthetics/params` + +=== {api-prereq-title} + +You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + +You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + +[[parameters-delete-request-body]] +==== Request Body + +The request body should contain an array of parameter IDs that you want to delete. + +`ids`:: +(Required, array of strings) An array of parameter IDs to delete. + + +Here is an example of a DELETE request to delete a list of parameters by ID: + +[source,sh] +-------------------------------------------------- +DELETE /api/synthetics/params +{ + "ids": [ + "param1-id", + "param2-id" + ] +} +-------------------------------------------------- + +[[parameters-delete-response-example]] +==== Response Example + +The API response includes information about the deleted parameters, where each entry in the response array contains the following attributes: + +- `id` (string): The unique identifier of the deleted parameter. +- `deleted` (boolean): Indicates whether the parameter was successfully deleted (`true` if deleted, `false` if not). + +Here's an example response for deleting multiple parameters: + +[source,sh] +-------------------------------------------------- +[ + { + "id": "param1-id", + "deleted": true + }, + { + "id": "param2-id", + "deleted": true + } +] +-------------------------------------------------- \ No newline at end of file diff --git a/docs/api/synthetics/params/edit-param.asciidoc b/docs/api/synthetics/params/edit-param.asciidoc new file mode 100644 index 00000000000000..e615dd0c0bd1f9 --- /dev/null +++ b/docs/api/synthetics/params/edit-param.asciidoc @@ -0,0 +1,70 @@ +[[edit-parameter-by-id-api]] +== Edit Parameter by ID API +++++ +Edit Parameter +++++ + +Edits a parameter with the specified ID. + +=== {api-request-title} + +`PUT :/api/synthetics/params` + +`PUT :/s//api/synthetics/params` + +=== {api-prereq-title} + +You must have `all` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + +[[parameter-edit-path-params]] +==== Path Parameters + +`id`:: +(Required, string) The unique identifier of the parameter to be edited. + +[[parameter-edit-request-body]] +==== Request body + +The request body should contain the following attributes: + +`key`:: +(Required, string) The key of the parameter. + +`value`:: +(Required, string) The updated value associated with the parameter. + +`description`:: +(Optional, string) The updated description of the parameter. + +`tags`:: +(Optional, array of strings) An array of updated tags to categorize the parameter. + +[[parameter-edit-example]] +==== Example + +Here is an example of a PUT request to edit a parameter by its ID: + +[source,sh] +-------------------------------------------------- +PUT /api/synthetics/params/param_id1 +{ + "key": "updated_param_key", + "value": "updated-param-value", + "description": "Updated Param to be used in browser monitor", + "tags": ["authentication", "security", "updated"] +} +-------------------------------------------------- + +The API returns the updated parameter as follows: + +[source,json] +-------------------------------------------------- +{ + "id": "param_id1", + "key": "updated_param_key", + "value": "updated-param-value", + "description": "Updated Param to be used in browser monitor", + "tags": ["authentication", "security", "updated"] +} +-------------------------------------------------- diff --git a/docs/api/synthetics/params/get-params.asciidoc b/docs/api/synthetics/params/get-params.asciidoc new file mode 100644 index 00000000000000..76356b28f76190 --- /dev/null +++ b/docs/api/synthetics/params/get-params.asciidoc @@ -0,0 +1,128 @@ +[[get-parameters-api]] +== Get Parameters API +++++ +Get Parameters +++++ + +Retrieves parameters based on the provided criteria. + +=== {api-request-title} + +`GET :/api/synthetics/params/{id?}` + +`GET :/s//api/synthetics/params/{id?}` + +=== {api-prereq-title} + +You must have `read` privileges for the *Synthetics* feature in the *{observability}* section of the +<>. + +[[parameters-get-query-params]] +==== Query Parameters + +`id`:: +(Optional, string) The unique identifier of the parameter. If provided, this API will retrieve a specific parameter by its ID. If not provided, it will retrieve a list of all parameters. + +[[parameters-get-response-example]] +==== Response Example + +The API response includes parameter(s) as JSON objects, where each parameter object has the following attributes: + +- `id` (string): The unique identifier of the parameter. +- `key` (string): The key of the parameter. + +If the user has read-only permissions to the Synthetics app, the following additional attributes will be included: + +- `description` (string, optional): The description of the parameter. +- `tags` (array of strings, optional): An array of tags associated with the parameter. +- `namespaces` (array of strings): Namespaces associated with the parameter. + +If the user has write permissions, the following additional attribute will be included: + +- `value` (string): The value associated with the parameter. + + +Here's an example request for retrieving a single parameter by its ID: + +[source,sh] +-------------------------------------------------- +GET /api/synthetics/params/unique-parameter-id +-------------------------------------------------- + + +Here's an example response for retrieving a single parameter by its ID: + +For users with read-only permissions: + +[source,json] +-------------------------------------------------- +{ + "id": "unique-parameter-id", + "key": "your-api-key", + "description": "Param to use in browser monitor", + "tags": ["authentication", "security"], + "namespaces": ["namespace1", "namespace2"] +} +-------------------------------------------------- + +For users with write permissions: + +[source,json] +-------------------------------------------------- +{ + "id": "unique-parameter-id", + "key": "your-param-key", + "description": "Param to use in browser monitor", + "tags": ["authentication", "security"], + "namespaces": ["namespace1", "namespace2"], + "value": "your-param-value" +} +-------------------------------------------------- + +And here's an example response for retrieving a list of parameters: + +For users with read-only permissions: + +[source,json] +-------------------------------------------------- +[ + { + "id": "param1-id", + "key": "param1", + "description": "Description for param1", + "tags": ["tag1", "tag2"], + "namespaces": ["namespace1"] + }, + { + "id": "param2-id", + "key": "param2", + "description": "Description for param2", + "tags": ["tag3"], + "namespaces": ["namespace2"] + } +] +-------------------------------------------------- + +For users with write permissions: + +[source,json] +-------------------------------------------------- +[ + { + "id": "param1-id", + "key": "param1", + "description": "Description for param1", + "tags": ["tag1", "tag2"], + "namespaces": ["namespace1"], + "value": "value1" + }, + { + "id": "param2-id", + "key": "param2", + "description": "Description for param2", + "tags": ["tag3"], + "namespaces": ["namespace2"], + "value": "value2" + } +] +-------------------------------------------------- \ No newline at end of file diff --git a/docs/api/synthetics/synthetics-api.asciidoc b/docs/api/synthetics/synthetics-api.asciidoc new file mode 100644 index 00000000000000..88a757670736a7 --- /dev/null +++ b/docs/api/synthetics/synthetics-api.asciidoc @@ -0,0 +1,18 @@ +[[synthetics-apis]] +== Synthetics APIs + +The following APIs are available for Synthetics. + +* <> to get a parameter(s). + +* <> to create a parameter. + +* <> to edit a parameter. + +* <> to delete a parameter. + + +include::params/add-param.asciidoc[leveloffset=+1] +include::params/get-params.asciidoc[leveloffset=+1] +include::params/edit-param.asciidoc[leveloffset=+1] +include::params/delete-param.asciidoc[leveloffset=+1] diff --git a/docs/user/api.asciidoc b/docs/user/api.asciidoc index 4358c448f3634a..7731a65baaac7d 100644 --- a/docs/user/api.asciidoc +++ b/docs/user/api.asciidoc @@ -109,4 +109,5 @@ include::{kib-repo-dir}/api/osquery-manager.asciidoc[] include::{kib-repo-dir}/api/short-urls.asciidoc[] include::{kib-repo-dir}/api/task-manager/health.asciidoc[] include::{kib-repo-dir}/api/upgrade-assistant.asciidoc[] +include::{kib-repo-dir}/api/synthetics/synthetics-api.asciidoc[] include::{kib-repo-dir}/api/uptime-api.asciidoc[] diff --git a/package.json b/package.json index e5213d00d20d46..5f144902b00e25 100644 --- a/package.json +++ b/package.json @@ -815,6 +815,7 @@ "@kbn/visualizations-plugin": "link:src/plugins/visualizations", "@kbn/watcher-plugin": "link:x-pack/plugins/watcher", "@kbn/xstate-utils": "link:packages/kbn-xstate-utils", + "@kbn/zod-helpers": "link:packages/kbn-zod-helpers", "@loaders.gl/core": "^3.4.7", "@loaders.gl/json": "^3.4.7", "@loaders.gl/shapefile": "^3.4.7", diff --git a/packages/core/logging/core-logging-common-internal/src/layouts/conversions/message.test.ts b/packages/core/logging/core-logging-common-internal/src/layouts/conversions/message.test.ts index a08f4742bb9782..cf16b57c927823 100644 --- a/packages/core/logging/core-logging-common-internal/src/layouts/conversions/message.test.ts +++ b/packages/core/logging/core-logging-common-internal/src/layouts/conversions/message.test.ts @@ -24,16 +24,16 @@ describe('MessageConversion', () => { ).toEqual('Hi!\nHow are you?'); }); - test('it should remove ANSI chars lines from the message', () => { + test('it should encode/escape ANSI chars lines from the message', () => { expect( MessageConversion.convert( { ...baseRecord, message: 'Blinking...\u001b[5;7;6mThis is Fine\u001b[27m' }, false ) - ).toEqual('Blinking...This is Fine'); + ).toEqual('Blinking...\\u001b[5;7;6mThis is Fine\\u001b[27m'); }); - test('it should remove any unicode injection from the message', () => { + test('it should encode/escape any unicode injection from the message', () => { expect( MessageConversion.convert( { @@ -43,6 +43,23 @@ describe('MessageConversion', () => { }, false ) - ).toEqual('ESC-INJECTION-LFUNICODE:SUCCESSFUL\n\nInjecting 10.000 lols 😂'); + ).toEqual( + '\\u001b[31mESC-INJECTION-LFUNICODE:\\u001b[32mSUCCESSFUL\\u001b[0m\\u0007\n\nInjecting 10.000 lols 😂\\u001b[10000;b\\u0007' + ); + }); + + test('it should encode/escape any unicode injection from the message (including nullbyte)', () => { + expect( + MessageConversion.convert( + { + ...baseRecord, + message: + '\u001b\u0000[31mESC-INJECTION-LFUNICODE:\u001b[32mSUCCESSFUL\u001b[0m\u0007\n\nInjecting 10.000 lols 😂\u001b[10000;b\u0007', + }, + false + ) + ).toEqual( + '\\u001b\\u0000[31mESC-INJECTION-LFUNICODE:\\u001b[32mSUCCESSFUL\\u001b[0m\\u0007\n\nInjecting 10.000 lols 😂\\u001b[10000;b\\u0007' + ); }); }); diff --git a/packages/core/logging/core-logging-common-internal/src/layouts/conversions/message.ts b/packages/core/logging/core-logging-common-internal/src/layouts/conversions/message.ts index 8bc9cd6c4115ac..706aa478d992b1 100644 --- a/packages/core/logging/core-logging-common-internal/src/layouts/conversions/message.ts +++ b/packages/core/logging/core-logging-common-internal/src/layouts/conversions/message.ts @@ -6,20 +6,28 @@ * Side Public License, v 1. */ -import ansiRegex from 'ansi-regex'; import { LogRecord } from '@kbn/logging'; import { Conversion } from './types'; -// Defining it globally because it's more performant than creating for each log entry -// We can reuse the same global RegExp here because `.replace()` automatically resets the `.lastIndex` of the RegExp. -const ANSI_ESCAPE_CODES_REGEXP = ansiRegex(); +// From https://www.ascii-code.com/characters/control-characters, +// but explicitly allowing the range \u0008-\u000F (line breaks, tabs, etc.) +const CONTROL_CHAR_REGEXP = new RegExp('[\\u0000-\\u0007\\u0010-\\u001F]', 'g'); export const MessageConversion: Conversion = { pattern: /%message/g, convert(record: LogRecord) { // Error stack is much more useful than just the message. const str = record.error?.stack || record.message; - // We need to validate it's a string because, despite types, there are use case where it's not a string :/ - return typeof str === 'string' ? str.replace(ANSI_ESCAPE_CODES_REGEXP, '') : str; + + return typeof str === 'string' // We need to validate it's a string because, despite types, there are use case where it's not a string :/ + ? str.replace( + CONTROL_CHAR_REGEXP, + // Escaping control chars via JSON.stringify to maintain consistency with `meta` and the JSON layout. + // This way, post analysis of the logs is easier as we can search the same patterns. + // Our benchmark didn't show a big difference in performance between custom-escaping vs. JSON.stringify one. + // The slice is removing the double-quotes. + (substr) => JSON.stringify(substr).slice(1, -1) + ) + : str; }, }; diff --git a/packages/kbn-doc-links/src/get_doc_links.ts b/packages/kbn-doc-links/src/get_doc_links.ts index 16b58be6c6c03d..a5f2bf8677cfd0 100644 --- a/packages/kbn-doc-links/src/get_doc_links.ts +++ b/packages/kbn-doc-links/src/get_doc_links.ts @@ -467,6 +467,7 @@ export const getDocLinks = ({ kibanaBranch }: GetDocLinkOptions): DocLinks => { luceneQuerySyntax: `${ELASTICSEARCH_DOCS}query-dsl-query-string-query.html#query-string-syntax`, percolate: `${ELASTICSEARCH_DOCS}query-dsl-percolate-query.html`, queryDsl: `${ELASTICSEARCH_DOCS}query-dsl.html`, + queryESQL: `${ELASTICSEARCH_DOCS}esql.html`, }, search: { sessions: `${KIBANA_DOCS}search-sessions.html`, diff --git a/packages/kbn-doc-links/src/types.ts b/packages/kbn-doc-links/src/types.ts index 703af63c1027c1..c2b90abf24aca8 100644 --- a/packages/kbn-doc-links/src/types.ts +++ b/packages/kbn-doc-links/src/types.ts @@ -358,6 +358,7 @@ export interface DocLinks { readonly luceneQuerySyntax: string; readonly percolate: string; readonly queryDsl: string; + readonly queryESQL: string; }; readonly date: { readonly dateMath: string; diff --git a/packages/kbn-es-archiver/src/actions/load.ts b/packages/kbn-es-archiver/src/actions/load.ts index 1cbdff1883271b..4a68281b6ab43a 100644 --- a/packages/kbn-es-archiver/src/actions/load.ts +++ b/packages/kbn-es-archiver/src/actions/load.ts @@ -30,6 +30,8 @@ import { createDefaultSpace, } from '../lib'; +import soOverrideAllowedList from '../fixtures/override_saved_objects_index/exception_list.json'; + // pipe a series of streams into each other so that data and errors // flow from the first stream to the last. Errors from the last stream // are not listened for @@ -38,6 +40,16 @@ const pipeline = (...streams: Readable[]) => source.once('error', (error) => dest.destroy(error)).pipe(dest as any) ); +const warningToUpdateArchive = (path: string) => { + return `This test is using '${path}' archive that contains saved object index definitions (in the 'mappings.json'). +This has proven to be a source of conflicts and flakiness, so the goal is to remove support for this feature ASAP. We kindly ask you to +update your test archives and remove SO index definitions, so that tests use the official saved object indices created by Kibana at startup. +You can achieve that by simply removing your saved object index definitions from 'mappings.json' (likely removing the file altogether). +We also recommend migrating existing tests to 'kbnArchiver' whenever possible. After the fix please remove archive path from the exception list: +${resolve(__dirname, '../fixtures/override_saved_objects_index/exception_list.json')}. +Find more information here: https://github.com/elastic/kibana/issues/161882`; +}; + export async function loadAction({ inputDir, skipExisting, @@ -56,6 +68,10 @@ export async function loadAction({ kbnClient: KbnClient; }) { const name = relative(REPO_ROOT, inputDir); + const isArchiveInExceptionList = soOverrideAllowedList.includes(name); + if (isArchiveInExceptionList) { + log.warning(warningToUpdateArchive(name)); + } const stats = createStats(name, log); const files = prioritizeMappings(await readDirectory(inputDir)); const kibanaPluginIds = await kbnClient.plugins.getEnabledIds(); @@ -80,7 +96,14 @@ export async function loadAction({ await createPromiseFromStreams([ recordStream, - createCreateIndexStream({ client, stats, skipExisting, docsOnly, log }), + createCreateIndexStream({ + client, + stats, + skipExisting, + docsOnly, + isArchiveInExceptionList, + log, + }), createIndexDocRecordsStream(client, stats, progress, useCreate), ]); diff --git a/packages/kbn-es-archiver/src/fixtures/override_saved_objects_index/exception_list.json b/packages/kbn-es-archiver/src/fixtures/override_saved_objects_index/exception_list.json new file mode 100644 index 00000000000000..be5cc4c893c109 --- /dev/null +++ b/packages/kbn-es-archiver/src/fixtures/override_saved_objects_index/exception_list.json @@ -0,0 +1,35 @@ +[ + "x-pack/test/functional/es_archives/action_task_params", + "x-pack/test/functional/es_archives/actions", + "x-pack/test/functional/es_archives/alerting/8_2_0", + "x-pack/test/functional/es_archives/alerts", + "x-pack/test/functional/es_archives/alerts_legacy/rules", + "x-pack/test/functional/es_archives/alerts_legacy/tasks", + "x-pack/test/functional/es_archives/cases/default", + "x-pack/test/functional/es_archives/cases/migrations/7.11.1", + "x-pack/test/functional/es_archives/cases/migrations/7.13.2", + "x-pack/test/functional/es_archives/cases/migrations/7.13_user_actions", + "x-pack/test/functional/es_archives/cases/migrations/7.16.0_space", + "x-pack/test/functional/es_archives/cases/migrations/8.8.0", + "x-pack/test/functional/es_archives/data/search_sessions", + "x-pack/test/functional/es_archives/endpoint/telemetry/agent_only", + "x-pack/test/functional/es_archives/endpoint/telemetry/cloned_endpoint_different_states", + "x-pack/test/functional/es_archives/endpoint/telemetry/cloned_endpoint_installed", + "x-pack/test/functional/es_archives/endpoint/telemetry/cloned_endpoint_uninstalled", + "x-pack/test/functional/es_archives/endpoint/telemetry/endpoint_malware_disabled", + "x-pack/test/functional/es_archives/endpoint/telemetry/endpoint_malware_enabled", + "x-pack/test/functional/es_archives/endpoint/telemetry/endpoint_uninstalled", + "x-pack/test/functional/es_archives/event_log_legacy_ids", + "x-pack/test/functional/es_archives/event_log_multiple_indicies", + "x-pack/test/functional/es_archives/fleet/agents", + "x-pack/test/functional/es_archives/lists", + "x-pack/test/functional/es_archives/rules_scheduled_task_id/rules", + "x-pack/test/functional/es_archives/rules_scheduled_task_id/tasks", + "x-pack/test/functional/es_archives/security_solution/import_rule_connector", + "x-pack/test/functional/es_archives/security_solution/migrations", + "x-pack/test/functional/es_archives/security_solution/resolve_read_rules/7_14", + "x-pack/test/functional/es_archives/security_solution/timelines/7.15.0", + "x-pack/test/functional/es_archives/security_solution/timelines/7.15.0_space", + "x-pack/test/functional/es_archives/task_manager_removed_types", + "x-pack/test/functional/es_archives/task_manager_tasks" +] diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts index a63eca8c9215d7..9f31a23492ba74 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.mock.ts @@ -6,7 +6,11 @@ * Side Public License, v 1. */ -import type { cleanSavedObjectIndices, deleteSavedObjectIndices } from './kibana_index'; +import type { + cleanSavedObjectIndices, + deleteSavedObjectIndices, + isSavedObjectIndex, +} from './kibana_index'; export const mockCleanSavedObjectIndices = jest.fn() as jest.MockedFunction< typeof cleanSavedObjectIndices @@ -16,7 +20,12 @@ export const mockDeleteSavedObjectIndices = jest.fn() as jest.MockedFunction< typeof deleteSavedObjectIndices >; +export const mockIsSavedObjectIndex = jest.fn() as unknown as jest.MockedFunction< + typeof isSavedObjectIndex +>; + jest.mock('./kibana_index', () => ({ cleanSavedObjectIndices: mockCleanSavedObjectIndices, deleteSavedObjectIndices: mockDeleteSavedObjectIndices, + isSavedObjectIndex: mockIsSavedObjectIndex, })); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts index 6ac0ce93bec2b9..0fc6921d648582 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.test.ts @@ -7,6 +7,7 @@ */ import { + mockIsSavedObjectIndex, mockCleanSavedObjectIndices, mockDeleteSavedObjectIndices, } from './create_index_stream.test.mock'; @@ -31,6 +32,7 @@ const chance = new Chance(); const log = createStubLogger(); beforeEach(() => { + mockIsSavedObjectIndex.mockClear(); mockCleanSavedObjectIndices.mockClear(); mockDeleteSavedObjectIndices.mockClear(); }); diff --git a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts index 3908ff375d0ddb..885563451137ef 100644 --- a/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts +++ b/packages/kbn-es-archiver/src/lib/indices/create_index_stream.ts @@ -19,7 +19,11 @@ import { TASK_MANAGER_SAVED_OBJECT_INDEX, } from '@kbn/core-saved-objects-server'; import { Stats } from '../stats'; -import { cleanSavedObjectIndices, deleteSavedObjectIndices } from './kibana_index'; +import { + cleanSavedObjectIndices, + deleteSavedObjectIndices, + isSavedObjectIndex, +} from './kibana_index'; import { deleteIndex } from './delete_index'; import { deleteDataStream } from './delete_data_stream'; import { ES_CLIENT_HEADERS } from '../../client_headers'; @@ -37,12 +41,14 @@ export function createCreateIndexStream({ stats, skipExisting = false, docsOnly = false, + isArchiveInExceptionList = false, log, }: { client: Client; stats: Stats; skipExisting?: boolean; docsOnly?: boolean; + isArchiveInExceptionList?: boolean; log: ToolingLog; }) { const skipDocsFromIndices = new Set(); @@ -129,6 +135,16 @@ export function createCreateIndexStream({ return; } + if (isSavedObjectIndex(index) && !isArchiveInExceptionList) { + throw new Error( + `'esArchiver' no longer supports defining saved object indices, your archive is modifying '${index}'. + The recommendation is to use 'kbnArchiver' to import saved objects in your tests. + If you absolutely need to load some non-importable SOs, please stick to the official saved object indices created by Kibana at startup. + You can achieve that by simply removing your saved object index definitions from 'mappings.json' (likely removing the file altogether). + Find more information here: https://github.com/elastic/kibana/issues/161882` + ); + } + async function attemptToCreate(attemptNumber = 1) { try { if (isKibana && !kibanaIndicesAlreadyDeleted) { diff --git a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts index e7a56b0c543067..02942c103aef85 100644 --- a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts @@ -85,7 +85,7 @@ export async function migrateSavedObjectIndices(kbnClient: KbnClient) { const LEGACY_INDICES_REGEXP = new RegExp(`^(${ALL_SAVED_OBJECT_INDICES.join('|')})(:?_\\d*)?$`); const INDICES_REGEXP = new RegExp(`^(${ALL_SAVED_OBJECT_INDICES.join('|')})_(pre)?\\d+.\\d+.\\d+`); -function isSavedObjectIndex(index?: string): index is string { +export function isSavedObjectIndex(index?: string): index is string { return Boolean(index && (LEGACY_INDICES_REGEXP.test(index) || INDICES_REGEXP.test(index))); } diff --git a/packages/kbn-es-archiver/tsconfig.json b/packages/kbn-es-archiver/tsconfig.json index 15fccdf68be4f1..bc3cee495a0522 100644 --- a/packages/kbn-es-archiver/tsconfig.json +++ b/packages/kbn-es-archiver/tsconfig.json @@ -8,7 +8,8 @@ ] }, "include": [ - "**/*.ts" + "**/*.ts", + "src/**/*.json" ], "kbn_references": [ "@kbn/core-saved-objects-server", diff --git a/packages/kbn-field-utils/src/types.ts b/packages/kbn-field-utils/src/types.ts index cfbc0339117a78..a0044975499814 100644 --- a/packages/kbn-field-utils/src/types.ts +++ b/packages/kbn-field-utils/src/types.ts @@ -21,6 +21,7 @@ export interface FieldBase { timeSeriesMetric?: DataViewField['timeSeriesMetric']; esTypes?: DataViewField['esTypes']; scripted?: DataViewField['scripted']; + conflictDescriptions?: Record; } export type GetCustomFieldType = (field: T) => FieldTypeKnown; diff --git a/packages/kbn-openapi-generator/kibana.jsonc b/packages/kbn-openapi-generator/kibana.jsonc index b507d94ec022d6..d0143b1523e883 100644 --- a/packages/kbn-openapi-generator/kibana.jsonc +++ b/packages/kbn-openapi-generator/kibana.jsonc @@ -1,6 +1,6 @@ { "devOnly": true, "id": "@kbn/openapi-generator", - "owner": "@elastic/security-detection-engine", + "owner": "@elastic/security-detection-rule-management", "type": "shared-common" } diff --git a/packages/kbn-openapi-generator/package.json b/packages/kbn-openapi-generator/package.json index 5847d729d025c9..8d72a1a8788656 100644 --- a/packages/kbn-openapi-generator/package.json +++ b/packages/kbn-openapi-generator/package.json @@ -1,7 +1,4 @@ { - "bin": { - "openapi-generator": "./bin/openapi-generator.js" - }, "description": "OpenAPI code generator for Kibana", "license": "SSPL-1.0 OR Elastic License 2.0", "name": "@kbn/openapi-generator", diff --git a/packages/kbn-openapi-generator/src/template_service/register_helpers.ts b/packages/kbn-openapi-generator/src/template_service/register_helpers.ts index 1431dafcdfba9f..72c6b50d126669 100644 --- a/packages/kbn-openapi-generator/src/template_service/register_helpers.ts +++ b/packages/kbn-openapi-generator/src/template_service/register_helpers.ts @@ -35,6 +35,12 @@ export function registerHelpers(handlebarsInstance: typeof Handlebars) { handlebarsInstance.registerHelper('defined', (val) => { return val !== undefined; }); + handlebarsInstance.registerHelper('first', (val) => { + return Array.isArray(val) ? val[0] : val; + }); + handlebarsInstance.registerHelper('isSingle', (val) => { + return Array.isArray(val) && val.length === 1; + }); /** * Check if the OpenAPI schema is unknown */ diff --git a/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars index 0b129b3aa13ed9..6bb6fccf7d3b32 100644 --- a/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars +++ b/packages/kbn-openapi-generator/src/template_service/templates/zod_operation_schema.handlebars @@ -6,6 +6,7 @@ */ import { z } from "zod"; +import { requiredOptional, isValidDateMath } from "@kbn/zod-helpers" {{> disclaimer}} @@ -24,8 +25,10 @@ import { export type {{@key}} = z.infer; export const {{@key}} = {{> zod_schema_item}}; {{#if enum}} -export const {{@key}}Enum = {{@key}}.enum; +{{#unless (isSingle enum)}} export type {{@key}}Enum = typeof {{@key}}.enum; +export const {{@key}}Enum = {{@key}}.enum; +{{/unless}} {{/if}} {{/each}} diff --git a/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars b/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars index dbf156b6a7b125..9a5312cf88f535 100644 --- a/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars +++ b/packages/kbn-openapi-generator/src/template_service/templates/zod_schema_item.handlebars @@ -10,6 +10,9 @@ {{~#if nullable}}.nullable(){{/if~}} {{~#if (eq requiredBool false)}}.optional(){{/if~}} {{~#if (defined default)}}.default({{{toJSON default}}}){{/if~}} + {{~#if (eq x-modify "partial")}}.partial(){{/if~}} + {{~#if (eq x-modify "required")}}.required(){{/if~}} + {{~#if (eq x-modify "requiredOptional")}}.transform(requiredOptional){{/if~}} {{~/if~}} {{~#if allOf~}} @@ -28,6 +31,8 @@ {{~> zod_schema_item ~}}, {{~/each~}} ]) + {{~#if nullable}}.nullable(){{/if~}} + {{~#if (eq requiredBool false)}}.optional(){{/if~}} {{~/if~}} {{~#if oneOf~}} @@ -36,6 +41,8 @@ {{~> zod_schema_item ~}}, {{~/each~}} ]) + {{~#if nullable}}.nullable(){{/if~}} + {{~#if (eq requiredBool false)}}.optional(){{/if~}} {{~/if~}} {{#if (isUnknown .)}} @@ -76,22 +83,38 @@ z.unknown() {{@key}}: {{> zod_schema_item requiredBool=(includes ../required @key)}}, {{/each}} }) - {{#if (eq additionalProperties false)}}.strict(){{/if}} + {{~#if (eq additionalProperties false)}}.strict(){{/if~}} + {{~#if additionalProperties}} + {{~#if (eq additionalProperties true)~}} + .catchall(z.unknown()) + {{~else~}} + .catchall({{> zod_schema_item additionalProperties}}) + {{~/if~}} + {{~/if~}} + {{~#if (eq x-modify "partial")}}.partial(){{/if~}} + {{~#if (eq x-modify "required")}}.required(){{/if~}} + {{~#if (eq x-modify "requiredOptional")}}.transform(requiredOptional){{/if~}} {{~/inline~}} {{~#*inline "type_string"~}} {{~#if enum~}} - z.enum([ - {{~#each enum~}} - "{{.}}", - {{~/each~}} - ]) + {{~#if (isSingle enum)~}} + z.literal("{{first enum}}") + {{~else~}} + z.enum([ + {{~#each enum~}} + "{{.}}", + {{~/each~}} + ]) + {{~/if~}} {{~else~}} z.string() {{~#if minLength}}.min({{minLength}}){{/if~}} {{~#if maxLength}}.max({{maxLength}}){{/if~}} {{~#if (eq format 'date-time')}}.datetime(){{/if~}} + {{~#if (eq format 'date-math')}}.superRefine(isValidDateMath){{/if~}} + {{~#if (eq format 'uuid')}}.uuid(){{/if~}} + {{~#if pattern}}.regex(/{{pattern}}/){{/if~}} {{~/if~}} - {{#if transform}}.transform({{{transform}}}){{/if~}} {{~/inline~}} diff --git a/packages/kbn-search-response-warnings/index.ts b/packages/kbn-search-response-warnings/index.ts index 413e8594bd8399..88b61320b99f73 100644 --- a/packages/kbn-search-response-warnings/index.ts +++ b/packages/kbn-search-response-warnings/index.ts @@ -9,10 +9,11 @@ export type { SearchResponseWarning, WarningHandlerCallback } from './src/types'; export { - SearchResponseWarnings, - type SearchResponseWarningsProps, + SearchResponseWarningsBadge, + SearchResponseWarningsBadgePopoverContent, + SearchResponseWarningsCallout, + SearchResponseWarningsEmptyPrompt, } from './src/components/search_response_warnings'; -export { ViewWarningButton } from './src/components/view_warning_button'; export { handleWarnings } from './src/handle_warnings'; export { hasUnsupportedDownsampledAggregationFailure } from './src/has_unsupported_downsampled_aggregation_failure'; diff --git a/packages/kbn-search-response-warnings/src/__mocks__/search_response_warnings.ts b/packages/kbn-search-response-warnings/src/__mocks__/search_response_warnings.ts index 6162ac1742f698..a2a9bbb134c05a 100644 --- a/packages/kbn-search-response-warnings/src/__mocks__/search_response_warnings.ts +++ b/packages/kbn-search-response-warnings/src/__mocks__/search_response_warnings.ts @@ -10,7 +10,7 @@ import type { SearchResponseWarning } from '../types'; export const searchResponseIncompleteWarningLocalCluster: SearchResponseWarning = { type: 'incomplete', - message: 'The data might be incomplete or wrong.', + requestName: 'My request', clusters: { '(local)': { status: 'partial', diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/__snapshots__/search_response_warnings.test.tsx.snap b/packages/kbn-search-response-warnings/src/components/search_response_warnings/__snapshots__/search_response_warnings.test.tsx.snap deleted file mode 100644 index d12cef130de2d6..00000000000000 --- a/packages/kbn-search-response-warnings/src/components/search_response_warnings/__snapshots__/search_response_warnings.test.tsx.snap +++ /dev/null @@ -1,176 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`SearchResponseWarnings renders "badge" correctly 1`] = ` -
-
- - - -
-
-`; - -exports[`SearchResponseWarnings renders "callout" correctly 1`] = ` -
-
    -
  • -
    -

    -

    -
    -
    -
    -
    -
    - The data might be incomplete or wrong. -
    -
    -
    -
    -
    -
    -
    -
    - -
    -
    -

    -

    -
  • -
-
-`; - -exports[`SearchResponseWarnings renders "empty_prompt" correctly 1`] = ` -
-
-
- -
-
-
-

- No results found -

-
-
-
    -
  • -
    -
    -
    - The data might be incomplete or wrong. -
    -
    -
    - -
    -
    -
  • -
-
-
-
-
-
-`; diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge.tsx new file mode 100644 index 00000000000000..5ae148c35a7ac6 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge.tsx @@ -0,0 +1,74 @@ +/* + * 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 React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; +import { css } from '@emotion/react'; +import { EuiButton, EuiIcon, EuiPopover, useEuiTheme, useEuiFontSize } from '@elastic/eui'; +import { SearchResponseWarningsBadgePopoverContent } from './badge_popover_content'; +import type { SearchResponseWarning } from '../../types'; + +interface Props { + warnings: SearchResponseWarning[]; +} + +export const SearchResponseWarningsBadge = (props: Props) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + const { euiTheme } = useEuiTheme(); + const xsFontSize = useEuiFontSize('xs').fontSize; + + if (!props.warnings.length) { + return null; + } + + return ( + setIsPopoverOpen(!isPopoverOpen)} + data-test-subj="searchResponseWarningsBadgeToogleButton" + title={i18n.translate('searchResponseWarnings.badgeButtonLabel', { + defaultMessage: '{warningCount} {warningCount, plural, one {warning} other {warnings}}', + values: { + warningCount: props.warnings.length, + }, + })} + css={css` + block-size: ${euiTheme.size.l}; + font-size: ${xsFontSize}; + padding: 0 ${euiTheme.size.xs}; + & > * { + gap: ${euiTheme.size.xs}; + } + `} + > + + {props.warnings.length} + + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)} + > + { + setIsPopoverOpen(false); + }} + warnings={props.warnings} + /> + + ); +}; diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge_popover_content.test.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge_popover_content.test.tsx new file mode 100644 index 00000000000000..9bc9cd5cef0275 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge_popover_content.test.tsx @@ -0,0 +1,119 @@ +/* + * 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 React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { SearchResponseWarningsBadgePopoverContent } from './badge_popover_content'; +import type { SearchResponseWarning } from '../../types'; + +describe('SearchResponseWarningsBadgePopoverContent', () => { + describe('single warning', () => { + test('Clicking "view details" should open warning details', () => { + const mockOpenInInspector = jest.fn(); + const mockOnViewDetailsClick = jest.fn(); + const warnings = [ + { + type: 'incomplete', + requestName: 'My request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: mockOpenInInspector, + } as SearchResponseWarning, + ]; + render( + + ); + const viewDetailsButton = screen.getByRole('button'); + fireEvent.click(viewDetailsButton); + expect(mockOpenInInspector).toHaveBeenCalled(); + expect(mockOnViewDetailsClick).toHaveBeenCalled(); + }); + }); + + describe('multiple warnings', () => { + const request1MockOpenInInspector = jest.fn(); + const request2MockOpenInInspector = jest.fn(); + const warnings = [ + { + type: 'incomplete', + requestName: 'My first request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: request1MockOpenInInspector, + } as SearchResponseWarning, + { + type: 'incomplete', + requestName: 'My second request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: request2MockOpenInInspector, + } as SearchResponseWarning, + ]; + + beforeEach(() => { + request1MockOpenInInspector.mockReset(); + request2MockOpenInInspector.mockReset(); + }); + + test('Clicking "view details" should open content panel with button to view details for each warning', () => { + const mockOnViewDetailsClick = jest.fn(); + render( + + ); + const viewDetailsButton = screen.getByRole('button'); + fireEvent.click(viewDetailsButton); + expect(request1MockOpenInInspector).not.toHaveBeenCalled(); + expect(request2MockOpenInInspector).not.toHaveBeenCalled(); + expect(mockOnViewDetailsClick).not.toHaveBeenCalled(); + + const openRequest1Button = screen.getByRole('button', { name: 'My first request' }); + fireEvent.click(openRequest1Button); + expect(request1MockOpenInInspector).toHaveBeenCalled(); + expect(mockOnViewDetailsClick).toHaveBeenCalled(); + expect(request2MockOpenInInspector).not.toHaveBeenCalled(); + }); + + test('Should ensure unique request names by numbering duplicate request names', () => { + const warningsWithDuplicateRequestNames = warnings.map((warning) => { + return { + ...warning, + requestName: 'Request', + }; + }); + render( + + ); + const viewDetailsButton = screen.getByRole('button'); + fireEvent.click(viewDetailsButton); + + screen.getByRole('button', { name: 'Request' }); + screen.getByRole('button', { name: 'Request (2)' }); + }); + }); +}); diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge_popover_content.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge_popover_content.tsx new file mode 100644 index 00000000000000..1c7537cfb64a11 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/badge_popover_content.tsx @@ -0,0 +1,85 @@ +/* + * 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 React, { useState } from 'react'; +import { + EuiButtonEmpty, + EuiContextMenuItem, + EuiContextMenuPanel, + EuiPanel, + EuiText, +} from '@elastic/eui'; +import { getWarningsDescription, getWarningsTitle, viewDetailsLabel } from './i18n_utils'; +import type { SearchResponseWarning } from '../../types'; + +const WARNING_PANEL_ID = 0; +const VIEW_DETAILS_PANEL_ID = 1; + +interface Props { + onViewDetailsClick?: () => void; + warnings: SearchResponseWarning[]; +} + +export const SearchResponseWarningsBadgePopoverContent = (props: Props) => { + const [openPanel, setOpenPanel] = useState(WARNING_PANEL_ID); + + const requestNameMap = new Map(); + return ( +
+ {openPanel === VIEW_DETAILS_PANEL_ID ? ( + { + const count = requestNameMap.has(warning.requestName) + ? requestNameMap.get(warning.requestName)! + 1 + : 1; + const uniqueRequestName = + count > 1 ? `${warning.requestName} (${count})` : warning.requestName; + requestNameMap.set(warning.requestName, count); + return ( + { + props.onViewDetailsClick?.(); + warning.openInInspector(); + }} + > + {uniqueRequestName} + + ); + })} + onClose={() => { + setOpenPanel(WARNING_PANEL_ID); + }} + title={viewDetailsLabel} + /> + ) : ( + + + {getWarningsDescription(props.warnings)} + 1 ? 'right' : undefined} + iconType={props.warnings.length > 1 ? 'arrowRight' : undefined} + onClick={() => { + if (props.warnings.length > 1) { + setOpenPanel(VIEW_DETAILS_PANEL_ID); + } else { + props.onViewDetailsClick?.(); + props.warnings[0].openInInspector(); + } + }} + > + {viewDetailsLabel} + + + + )} +
+ ); +}; diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/callout.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/callout.tsx new file mode 100644 index 00000000000000..448d08fd5bdfc7 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/callout.tsx @@ -0,0 +1,40 @@ +/* + * 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 React from 'react'; +import { EuiCallOut, EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; +import { ViewDetailsPopover } from './view_details_popover'; +import { getWarningsDescription, getWarningsTitle } from './i18n_utils'; +import type { SearchResponseWarning } from '../../types'; + +interface Props { + warnings: SearchResponseWarning[]; +} + +export const SearchResponseWarningsCallout = (props: Props) => { + if (!props.warnings.length) { + return null; + } + + return ( + + + {getWarningsDescription(props.warnings)} + + + + + + ); +}; diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/empty_prompt.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/empty_prompt.tsx new file mode 100644 index 00000000000000..097cc7a314cf92 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/empty_prompt.tsx @@ -0,0 +1,37 @@ +/* + * 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 React from 'react'; +import { i18n } from '@kbn/i18n'; +import { EuiEmptyPrompt } from '@elastic/eui'; +import { ViewDetailsPopover } from './view_details_popover'; +import { getWarningsDescription } from './i18n_utils'; +import type { SearchResponseWarning } from '../../types'; + +interface Props { + warnings: SearchResponseWarning[]; +} + +export const SearchResponseWarningsEmptyPrompt = (props: Props) => { + return ( + + {i18n.translate('searchResponseWarnings.noResultsTitle', { + defaultMessage: 'No results found', + })} + + } + body={getWarningsDescription(props.warnings)} + actions={} + data-test-subj="searchResponseWarningsEmptyPrompt" + /> + ); +}; diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.test.ts b/packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.test.ts new file mode 100644 index 00000000000000..ed8c26135185a3 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.test.ts @@ -0,0 +1,130 @@ +/* + * 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 { getWarningsTitle, getWarningsDescription } from './i18n_utils'; +import type { SearchResponseWarning } from '../../types'; + +describe('getWarningsTitle', () => { + test('Should show title for single non-successful cluster', () => { + const warnings = [ + { + type: 'incomplete', + requestName: 'My request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: () => {}, + } as SearchResponseWarning, + ]; + expect(getWarningsTitle(warnings)).toEqual('Problem with 1 cluster'); + }); + + test('Should show title for multiple non-successful cluster', () => { + const warnings = [ + { + type: 'incomplete', + requestName: 'My request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + remote2: { + status: 'skipped', + indices: '', + timed_out: false, + }, + }, + openInInspector: () => {}, + } as SearchResponseWarning, + ]; + expect(getWarningsTitle(warnings)).toEqual('Problem with 2 clusters'); + }); + + test('Should show title for multiple requests', () => { + const warnings = [ + { + type: 'incomplete', + requestName: 'My request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: () => {}, + } as SearchResponseWarning, + { + type: 'incomplete', + requestName: 'My request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: () => {}, + } as SearchResponseWarning, + ]; + expect(getWarningsTitle(warnings)).toEqual('Problem with 1 cluster in 2 requests'); + }); +}); + +describe('getWarningsDescription', () => { + test('Should show description for single non-successful cluster', () => { + const warnings = [ + { + type: 'incomplete', + requestName: 'My request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: () => {}, + } as SearchResponseWarning, + ]; + expect(getWarningsDescription(warnings)).toEqual( + 'This cluster had issues returning data and results might be incomplete.' + ); + }); + + test('Should show description for multiple non-successful cluster', () => { + const warnings = [ + { + type: 'incomplete', + requestName: 'My request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + remote2: { + status: 'skipped', + indices: '', + timed_out: false, + }, + }, + openInInspector: () => {}, + } as SearchResponseWarning, + ]; + expect(getWarningsDescription(warnings)).toEqual( + 'These clusters had issues returning data and results might be incomplete.' + ); + }); +}); diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.ts b/packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.ts new file mode 100644 index 00000000000000..7a7ebd196097b2 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/i18n_utils.ts @@ -0,0 +1,57 @@ +/* + * 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 { i18n } from '@kbn/i18n'; +import type { SearchResponseWarning } from '../../types'; + +export const viewDetailsLabel = i18n.translate('searchResponseWarnings.viewDetailsButtonLabel', { + defaultMessage: 'View details', + description: 'View warning details button label', +}); + +export function getNonSuccessfulClusters(warnings: SearchResponseWarning[]) { + const nonSuccessfulClusters = new Set(); + warnings.forEach((warning) => { + Object.keys(warning.clusters).forEach((clusterName) => { + if (warning.clusters[clusterName].status !== 'successful') { + nonSuccessfulClusters.add(clusterName); + } + }); + }); + return nonSuccessfulClusters; +} + +export function getWarningsTitle(warnings: SearchResponseWarning[]) { + const nonSuccessfulClusters = getNonSuccessfulClusters(warnings); + const clustersClause = i18n.translate('searchResponseWarnings.title.clustersClause', { + defaultMessage: + 'Problem with {nonSuccessfulClustersCount} {nonSuccessfulClustersCount, plural, one {cluster} other {clusters}}', + values: { nonSuccessfulClustersCount: nonSuccessfulClusters.size }, + }); + + return warnings.length <= 1 + ? clustersClause + : i18n.translate('searchResponseWarnings.title.clustersClauseAndRequestsClause', { + defaultMessage: '{clustersClause} in {requestsCount} requests', + values: { + clustersClause, + requestsCount: warnings.length, + }, + }); +} + +export function getWarningsDescription(warnings: SearchResponseWarning[]) { + const nonSuccessfulClusters = getNonSuccessfulClusters(warnings); + return nonSuccessfulClusters.size <= 1 + ? i18n.translate('searchResponseWarnings.description.singleCluster', { + defaultMessage: 'This cluster had issues returning data and results might be incomplete.', + }) + : i18n.translate('searchResponseWarnings.description.multipleClusters', { + defaultMessage: 'These clusters had issues returning data and results might be incomplete.', + }); +} diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/index.ts b/packages/kbn-search-response-warnings/src/components/search_response_warnings/index.ts index 8a3ed6d05600e0..06c2b2c18e31a1 100644 --- a/packages/kbn-search-response-warnings/src/components/search_response_warnings/index.ts +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/index.ts @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -export { - SearchResponseWarnings, - type SearchResponseWarningsProps, -} from './search_response_warnings'; +export { SearchResponseWarningsBadge } from './badge'; +export { SearchResponseWarningsBadgePopoverContent } from './badge_popover_content'; +export { SearchResponseWarningsCallout } from './callout'; +export { SearchResponseWarningsEmptyPrompt } from './empty_prompt'; diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.test.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.test.tsx deleted file mode 100644 index aa4e4ba1636814..00000000000000 --- a/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.test.tsx +++ /dev/null @@ -1,49 +0,0 @@ -/* - * 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 React from 'react'; -import { mountWithIntl } from '@kbn/test-jest-helpers'; -import { SearchResponseWarnings } from './search_response_warnings'; -import { searchResponseIncompleteWarningLocalCluster } from '../../__mocks__/search_response_warnings'; - -const interceptedWarnings = [searchResponseIncompleteWarningLocalCluster]; - -describe('SearchResponseWarnings', () => { - it('renders "callout" correctly', () => { - const component = mountWithIntl( - - ); - expect(component.render()).toMatchSnapshot(); - }); - - it('renders "badge" correctly', () => { - const component = mountWithIntl( - - ); - expect(component.render()).toMatchSnapshot(); - }); - - it('renders "empty_prompt" correctly', () => { - const component = mountWithIntl( - - ); - expect(component.render()).toMatchSnapshot(); - }); -}); diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx deleted file mode 100644 index baa45b9c0a93bb..00000000000000 --- a/packages/kbn-search-response-warnings/src/components/search_response_warnings/search_response_warnings.tsx +++ /dev/null @@ -1,313 +0,0 @@ -/* - * 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 React, { PropsWithChildren, useEffect, useState } from 'react'; -import { - EuiCallOut, - EuiEmptyPrompt, - EuiText, - EuiTextProps, - EuiFlexGroup, - EuiFlexGroupProps, - EuiFlexItem, - EuiToolTip, - EuiButton, - EuiIcon, - EuiPopover, - useEuiTheme, - useEuiFontSize, - EuiButtonIcon, -} from '@elastic/eui'; -import { css } from '@emotion/react'; -import { i18n } from '@kbn/i18n'; -import { ViewWarningButton } from '../view_warning_button'; -import type { SearchResponseWarning } from '../../types'; - -/** - * SearchResponseWarnings component props - */ -export interface SearchResponseWarningsProps { - /** - * An array of warnings - */ - interceptedWarnings?: SearchResponseWarning[]; - - /** - * View variant - */ - variant: 'callout' | 'badge' | 'empty_prompt'; - - /** - * Custom data-test-subj value - */ - 'data-test-subj': string; -} - -/** - * SearchResponseWarnings component - * @param interceptedWarnings - * @param variant - * @param dataTestSubj - * @constructor - */ -export const SearchResponseWarnings = ({ - interceptedWarnings, - variant, - 'data-test-subj': dataTestSubj, -}: SearchResponseWarningsProps) => { - const { euiTheme } = useEuiTheme(); - const xsFontSize = useEuiFontSize('xs').fontSize; - const [isCalloutVisibleMap, setIsCalloutVisibleMap] = useState>({}); - const [isPopoverOpen, setIsPopoverOpen] = useState(false); - - useEffect(() => { - setIsCalloutVisibleMap({}); - }, [interceptedWarnings, setIsCalloutVisibleMap]); - - if (!interceptedWarnings?.length) { - return null; - } - - if (variant === 'callout') { - return ( -
-
    - {interceptedWarnings.map((warning, index) => { - if (isCalloutVisibleMap[index] === false) { - return null; - } - return ( -
  • - - setIsCalloutVisibleMap((prev) => ({ ...prev, [index]: false })) - } - > - - - } - color="warning" - iconType="warning" - size="s" - css={css` - .euiTitle { - display: flex; - align-items: center; - } - `} - data-test-subj={dataTestSubj} - /> -
  • - ); - })} -
-
- ); - } - - if (variant === 'empty_prompt') { - return ( - - {i18n.translate('searchResponseWarnings.noResultsTitle', { - defaultMessage: 'No results found', - })} - - } - body={ -
    - {interceptedWarnings.map((warning, index) => ( -
  • - -
  • - ))} -
- } - /> - ); - } - - if (variant === 'badge') { - const warningCount = interceptedWarnings.length; - const buttonLabel = i18n.translate('searchResponseWarnings.badgeButtonLabel', { - defaultMessage: '{warningCount} {warningCount, plural, one {warning} other {warnings}}', - values: { - warningCount, - }, - }); - - return ( - - setIsPopoverOpen(true)} - data-test-subj={`${dataTestSubj}_trigger`} - title={buttonLabel} - css={css` - block-size: ${euiTheme.size.l}; - font-size: ${xsFontSize}; - padding: 0 ${euiTheme.size.xs}; - & > * { - gap: ${euiTheme.size.xs}; - } - `} - > - - {warningCount} - - - } - isOpen={isPopoverOpen} - closePopover={() => setIsPopoverOpen(false)} - > -
    - {interceptedWarnings.map((warning, index) => ( -
  • - - - - - - - - -
  • - ))} -
-
- ); - } - - return null; -}; - -function WarningContent({ - warning, - textSize = 's', - groupStyles, - 'data-test-subj': dataTestSubj, -}: { - warning: SearchResponseWarning; - textSize?: EuiTextProps['size']; - groupStyles?: Partial; - 'data-test-subj': string; -}) { - return ( - - - - {warning.message} - - - - - - - ); -} - -function CalloutTitleWrapper({ - children, - onCloseCallout, -}: PropsWithChildren<{ onCloseCallout: () => void }>) { - return ( - - {children} - - - - - ); -} diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/view_details_popover.test.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/view_details_popover.test.tsx new file mode 100644 index 00000000000000..7cf0d545e20170 --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/view_details_popover.test.tsx @@ -0,0 +1,128 @@ +/* + * 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 React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { ViewDetailsPopover } from './view_details_popover'; +import type { SearchResponseWarning } from '../../types'; + +describe('ViewDetailsPopover', () => { + describe('single warning', () => { + const mockOpenInInspector = jest.fn(); + const warnings = [ + { + type: 'incomplete', + requestName: 'My request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: mockOpenInInspector, + } as SearchResponseWarning, + ]; + + beforeEach(() => { + mockOpenInInspector.mockReset(); + }); + + test('Clicking "view details" button should open warning details', () => { + render(); + const viewDetailsButton = screen.getByRole('button'); + fireEvent.click(viewDetailsButton); + expect(mockOpenInInspector).toHaveBeenCalled(); + }); + + test('Clicking "view details" link should open warning details', () => { + render(); + const viewDetailsButton = screen.getByRole('button'); + fireEvent.click(viewDetailsButton); + expect(mockOpenInInspector).toHaveBeenCalled(); + }); + }); + + describe('multiple warnings', () => { + const request1MockOpenInInspector = jest.fn(); + const request2MockOpenInInspector = jest.fn(); + const warnings = [ + { + type: 'incomplete', + requestName: 'My first request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: request1MockOpenInInspector, + } as SearchResponseWarning, + { + type: 'incomplete', + requestName: 'My second request', + clusters: { + remote1: { + status: 'partial', + indices: '', + timed_out: false, + }, + }, + openInInspector: request2MockOpenInInspector, + } as SearchResponseWarning, + ]; + beforeEach(() => { + request1MockOpenInInspector.mockReset(); + request2MockOpenInInspector.mockReset(); + }); + + test('Clicking "view details" button should open popover with button to view details for each warning', () => { + render(); + const viewDetailsButton = screen.getByRole('button'); + fireEvent.click(viewDetailsButton); + expect(request1MockOpenInInspector).not.toHaveBeenCalled(); + expect(request2MockOpenInInspector).not.toHaveBeenCalled(); + + const openRequest1Button = screen.getByRole('button', { name: 'My first request' }); + fireEvent.click(openRequest1Button); + expect(request1MockOpenInInspector).toHaveBeenCalled(); + expect(request2MockOpenInInspector).not.toHaveBeenCalled(); + }); + + test('Clicking "view details" link should open popover with button to view details for each warning', () => { + render(); + const viewDetailsButton = screen.getByRole('button'); + fireEvent.click(viewDetailsButton); + expect(request1MockOpenInInspector).not.toHaveBeenCalled(); + expect(request2MockOpenInInspector).not.toHaveBeenCalled(); + + const openRequest1Button = screen.getByRole('button', { name: 'My first request' }); + fireEvent.click(openRequest1Button); + expect(request1MockOpenInInspector).toHaveBeenCalled(); + expect(request2MockOpenInInspector).not.toHaveBeenCalled(); + }); + + test('Should ensure unique request names by numbering duplicate request names', () => { + const warningsWithDuplicateRequestNames = warnings.map((warning) => { + return { + ...warning, + requestName: 'Request', + }; + }); + render( + + ); + const viewDetailsButton = screen.getByRole('button'); + fireEvent.click(viewDetailsButton); + + screen.getByRole('button', { name: 'Request' }); + screen.getByRole('button', { name: 'Request (2)' }); + }); + }); +}); diff --git a/packages/kbn-search-response-warnings/src/components/search_response_warnings/view_details_popover.tsx b/packages/kbn-search-response-warnings/src/components/search_response_warnings/view_details_popover.tsx new file mode 100644 index 00000000000000..98c5a08f9b2d8a --- /dev/null +++ b/packages/kbn-search-response-warnings/src/components/search_response_warnings/view_details_popover.tsx @@ -0,0 +1,96 @@ +/* + * 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 React, { useState } from 'react'; +import { + EuiButton, + EuiIcon, + EuiLink, + EuiContextMenu, + EuiContextMenuPanelDescriptor, + EuiPopover, +} from '@elastic/eui'; +import { viewDetailsLabel } from './i18n_utils'; +import type { SearchResponseWarning } from '../../types'; + +interface Props { + displayAsLink?: boolean; + warnings: SearchResponseWarning[]; +} + +export const ViewDetailsPopover = (props: Props) => { + const [isPopoverOpen, setIsPopoverOpen] = useState(false); + + if (!props.warnings.length) { + return null; + } + + if (props.warnings.length === 1) { + return props.displayAsLink ? ( + + {viewDetailsLabel} + + ) : ( + + {viewDetailsLabel} + + ); + } + + const requestNameMap = new Map(); + const panels: EuiContextMenuPanelDescriptor[] = [ + { + id: 0, + items: props.warnings.map((warning) => { + const count = requestNameMap.has(warning.requestName) + ? requestNameMap.get(warning.requestName)! + 1 + : 1; + const uniqueRequestName = + count > 1 ? `${warning.requestName} (${count})` : warning.requestName; + requestNameMap.set(warning.requestName, count); + return { + name: uniqueRequestName, + onClick: () => { + setIsPopoverOpen(false); + warning.openInInspector(); + }, + }; + }), + }, + ]; + + return ( + setIsPopoverOpen(!isPopoverOpen)}> + <> + {viewDetailsLabel} + + + ) : ( + setIsPopoverOpen(!isPopoverOpen)} + iconSide="right" + iconType="arrowRight" + > + {viewDetailsLabel} + + ) + } + isOpen={isPopoverOpen} + closePopover={() => setIsPopoverOpen(false)} + panelPaddingSize="none" + anchorPosition="downCenter" + > + + + ); +}; diff --git a/packages/kbn-search-response-warnings/src/components/view_warning_button/view_warning_button.tsx b/packages/kbn-search-response-warnings/src/components/view_warning_button/view_warning_button.tsx deleted file mode 100644 index bd0e717d9c76dd..00000000000000 --- a/packages/kbn-search-response-warnings/src/components/view_warning_button/view_warning_button.tsx +++ /dev/null @@ -1,39 +0,0 @@ -/* - * 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 React from 'react'; -import { FormattedMessage } from '@kbn/i18n-react'; -import { EuiLink, EuiButton, EuiButtonProps } from '@elastic/eui'; - -export interface Props { - onClick: () => void; - size?: EuiButtonProps['size']; - color?: EuiButtonProps['color']; - isButtonEmpty?: boolean; -} - -// Needed for React.lazy -// eslint-disable-next-line import/no-default-export -export default function ViewWarningButton({ - onClick, - size = 's', - color = 'warning', - isButtonEmpty = false, -}: Props) { - const Component = isButtonEmpty ? EuiLink : EuiButton; - - return ( - - - - ); -} diff --git a/packages/kbn-search-response-warnings/src/extract_warnings.test.ts b/packages/kbn-search-response-warnings/src/extract_warnings.test.ts index f2a2e9f63d29b7..e0f3388d5f68cf 100644 --- a/packages/kbn-search-response-warnings/src/extract_warnings.test.ts +++ b/packages/kbn-search-response-warnings/src/extract_warnings.test.ts @@ -42,10 +42,12 @@ describe('extract search response warnings', () => { aggregations: {}, }; - expect(extractWarnings(response, mockInspectorService, mockRequestAdapter)).toEqual([ + expect( + extractWarnings(response, mockInspectorService, mockRequestAdapter, 'My request') + ).toEqual([ { type: 'incomplete', - message: 'Results are partial and may be incomplete.', + requestName: 'My request', clusters: { '(local)': { status: 'partial', @@ -68,10 +70,12 @@ describe('extract search response warnings', () => { _shards: {} as estypes.ShardStatistics, hits: { hits: [] }, }; - expect(extractWarnings(response, mockInspectorService, mockRequestAdapter)).toEqual([ + expect( + extractWarnings(response, mockInspectorService, mockRequestAdapter, 'My request') + ).toEqual([ { type: 'incomplete', - message: 'Results are partial and may be incomplete.', + requestName: 'My request', clusters: { '(local)': { status: 'partial', @@ -97,7 +101,8 @@ describe('extract search response warnings', () => { }, } as estypes.SearchResponse, mockInspectorService, - mockRequestAdapter + mockRequestAdapter, + 'My request' ); expect(warnings).toEqual([]); @@ -188,10 +193,12 @@ describe('extract search response warnings', () => { aggregations: {}, }; - expect(extractWarnings(response, mockInspectorService, mockRequestAdapter)).toEqual([ + expect( + extractWarnings(response, mockInspectorService, mockRequestAdapter, 'My request') + ).toEqual([ { type: 'incomplete', - message: 'Results are partial and may be incomplete.', + requestName: 'My request', clusters: response._clusters.details, openInInspector: expect.any(Function), }, @@ -242,10 +249,12 @@ describe('extract search response warnings', () => { }, hits: { hits: [] }, }; - expect(extractWarnings(response, mockInspectorService, mockRequestAdapter)).toEqual([ + expect( + extractWarnings(response, mockInspectorService, mockRequestAdapter, 'My request') + ).toEqual([ { type: 'incomplete', - message: 'Results are partial and may be incomplete.', + requestName: 'My request', clusters: response._clusters.details, openInInspector: expect.any(Function), }, @@ -297,7 +306,8 @@ describe('extract search response warnings', () => { hits: { hits: [] }, } as estypes.SearchResponse, mockInspectorService, - mockRequestAdapter + mockRequestAdapter, + 'My request' ); expect(warnings).toEqual([]); diff --git a/packages/kbn-search-response-warnings/src/extract_warnings.ts b/packages/kbn-search-response-warnings/src/extract_warnings.ts index 2bab91525609b5..f11b424694ec18 100644 --- a/packages/kbn-search-response-warnings/src/extract_warnings.ts +++ b/packages/kbn-search-response-warnings/src/extract_warnings.ts @@ -7,7 +7,6 @@ */ import { estypes } from '@elastic/elasticsearch'; -import { i18n } from '@kbn/i18n'; import type { ClusterDetails } from '@kbn/es-types'; import type { Start as InspectorStartContract, RequestAdapter } from '@kbn/inspector-plugin/public'; import type { SearchResponseWarning } from './types'; @@ -19,6 +18,7 @@ export function extractWarnings( rawResponse: estypes.SearchResponse, inspectorService: InspectorStartContract, requestAdapter: RequestAdapter, + requestName: string, requestId?: string ): SearchResponseWarning[] { const warnings: SearchResponseWarning[] = []; @@ -35,9 +35,7 @@ export function extractWarnings( if (isPartial) { warnings.push({ type: 'incomplete', - message: i18n.translate('searchResponseWarnings.incompleteResultsMessage', { - defaultMessage: 'Results are partial and may be incomplete.', - }), + requestName, clusters: rawResponse._clusters ? ( rawResponse._clusters as estypes.ClusterStatistics & { diff --git a/packages/kbn-search-response-warnings/src/handle_warnings.test.ts b/packages/kbn-search-response-warnings/src/handle_warnings.test.ts index 0ec94c4d8ebbf3..ad9dff53fdf5ea 100644 --- a/packages/kbn-search-response-warnings/src/handle_warnings.test.ts +++ b/packages/kbn-search-response-warnings/src/handle_warnings.test.ts @@ -25,6 +25,7 @@ describe('handleWarnings', () => { request: {} as unknown as estypes.SearchRequest, requestAdapter: {} as unknown as RequestAdapter, requestId: '1234', + requestName: 'My request', response: { timed_out: false, _shards: { @@ -48,6 +49,7 @@ describe('handleWarnings', () => { request: {} as unknown as estypes.SearchRequest, requestAdapter: {} as unknown as RequestAdapter, requestId: '1234', + requestName: 'My request', response: { took: 999, timed_out: true, @@ -72,6 +74,7 @@ describe('handleWarnings', () => { request: {} as unknown as estypes.SearchRequest, requestAdapter: {} as unknown as RequestAdapter, requestId: '1234', + requestName: 'My request', response: { took: 999, timed_out: true, @@ -97,6 +100,7 @@ describe('handleWarnings', () => { request: {} as unknown as estypes.SearchRequest, requestAdapter: {} as unknown as RequestAdapter, requestId: '1234', + requestName: 'My request', response: { took: 999, timed_out: true, diff --git a/packages/kbn-search-response-warnings/src/handle_warnings.tsx b/packages/kbn-search-response-warnings/src/handle_warnings.tsx index 343db1c4a789fd..1ff5cb0eafab4e 100644 --- a/packages/kbn-search-response-warnings/src/handle_warnings.tsx +++ b/packages/kbn-search-response-warnings/src/handle_warnings.tsx @@ -7,7 +7,7 @@ */ import React from 'react'; -import { EuiTextAlign } from '@elastic/eui'; +import { EuiButtonEmpty, EuiText } from '@elastic/eui'; import { estypes } from '@elastic/elasticsearch'; import type { NotificationsStart, ThemeServiceStart } from '@kbn/core/public'; import { toMountPoint } from '@kbn/react-kibana-mount'; @@ -19,7 +19,11 @@ import { WarningHandlerCallback, } from './types'; import { extractWarnings } from './extract_warnings'; -import { ViewWarningButton } from './components/view_warning_button'; +import { + getWarningsDescription, + getWarningsTitle, + viewDetailsLabel, +} from './components/search_response_warnings/i18n_utils'; interface Services { i18n: I18nStart; @@ -36,6 +40,7 @@ export function handleWarnings({ callback, request, requestId, + requestName, requestAdapter, response, services, @@ -44,10 +49,17 @@ export function handleWarnings({ request: estypes.SearchRequest; requestAdapter: RequestAdapter; requestId?: string; + requestName: string; response: estypes.SearchResponse; services: Services; }) { - const warnings = extractWarnings(response, services.inspector, requestAdapter, requestId); + const warnings = extractWarnings( + response, + services.inspector, + requestAdapter, + requestName, + requestId + ); if (warnings.length === 0) { return; } @@ -67,11 +79,21 @@ export function handleWarnings({ const [incompleteWarning] = incompleteWarnings as SearchResponseIncompleteWarning[]; services.notifications.toasts.addWarning({ - title: incompleteWarning.message, + title: getWarningsTitle([incompleteWarning]), text: toMountPoint( - - - , + <> + {getWarningsDescription([incompleteWarning])} + { + incompleteWarning.openInInspector(); + }} + data-test-subj="viewWarningBtn" + > + {viewDetailsLabel} + + , { theme: services.theme, i18n: services.i18n } ), }); diff --git a/packages/kbn-search-response-warnings/src/has_unsupported_downsampled_aggregation_failure.test.ts b/packages/kbn-search-response-warnings/src/has_unsupported_downsampled_aggregation_failure.test.ts index ec99f9ba8822bb..42362965a77993 100644 --- a/packages/kbn-search-response-warnings/src/has_unsupported_downsampled_aggregation_failure.test.ts +++ b/packages/kbn-search-response-warnings/src/has_unsupported_downsampled_aggregation_failure.test.ts @@ -13,7 +13,7 @@ describe('hasUnsupportedDownsampledAggregationFailure', () => { expect( hasUnsupportedDownsampledAggregationFailure({ type: 'incomplete', - message: 'The data might be incomplete or wrong.', + requestName: 'My request', clusters: { '(local)': { status: 'partial', @@ -49,7 +49,7 @@ describe('hasUnsupportedDownsampledAggregationFailure', () => { expect( hasUnsupportedDownsampledAggregationFailure({ type: 'incomplete', - message: 'The data might be incomplete or wrong.', + requestName: 'My request', clusters: { '(local)': { status: 'partial', diff --git a/packages/kbn-search-response-warnings/src/types.ts b/packages/kbn-search-response-warnings/src/types.ts index d7df71b40d71d2..df55e012ff7ae2 100644 --- a/packages/kbn-search-response-warnings/src/types.ts +++ b/packages/kbn-search-response-warnings/src/types.ts @@ -25,9 +25,9 @@ export interface SearchResponseIncompleteWarning { */ type: 'incomplete'; /** - * message: human-friendly message + * requestName: human-friendly request name */ - message: string; + requestName: string; /** * clusters: cluster details. */ diff --git a/packages/kbn-search-response-warnings/tsconfig.json b/packages/kbn-search-response-warnings/tsconfig.json index 26819b76e3e529..963dff502604fb 100644 --- a/packages/kbn-search-response-warnings/tsconfig.json +++ b/packages/kbn-search-response-warnings/tsconfig.json @@ -5,11 +5,9 @@ }, "include": ["*.ts", "src/**/*", "__mocks__/**/*.ts"], "kbn_references": [ - "@kbn/test-jest-helpers", "@kbn/i18n", "@kbn/inspector-plugin", "@kbn/core", - "@kbn/i18n-react", "@kbn/es-types", "@kbn/react-kibana-mount", "@kbn/core-i18n-browser", diff --git a/packages/kbn-securitysolution-es-utils/src/transform_error/index.ts b/packages/kbn-securitysolution-es-utils/src/transform_error/index.ts index 3a4386547e1c04..d893a3e1b4ed7f 100644 --- a/packages/kbn-securitysolution-es-utils/src/transform_error/index.ts +++ b/packages/kbn-securitysolution-es-utils/src/transform_error/index.ts @@ -6,8 +6,9 @@ * Side Public License, v 1. */ -import Boom from '@hapi/boom'; import { errors } from '@elastic/elasticsearch'; +import Boom from '@hapi/boom'; +import { stringifyZodError } from '@kbn/zod-helpers'; import { ZodError } from 'zod'; import { BadRequestError } from '../bad_request_error'; @@ -60,15 +61,3 @@ export const transformError = (err: Error & Partial): Outp } } }; - -export function stringifyZodError(err: ZodError) { - return err.issues - .map((issue) => { - // If the path is empty, the error is for the root object - if (issue.path.length === 0) { - return issue.message; - } - return `${issue.path.join('.')}: ${issue.message}`; - }) - .join(', '); -} diff --git a/packages/kbn-securitysolution-es-utils/tsconfig.json b/packages/kbn-securitysolution-es-utils/tsconfig.json index 9bd4f35cf62a7e..c9296a28f35c7f 100644 --- a/packages/kbn-securitysolution-es-utils/tsconfig.json +++ b/packages/kbn-securitysolution-es-utils/tsconfig.json @@ -12,5 +12,8 @@ ], "exclude": [ "target/**/*", + ], + "kbn_references": [ + "@kbn/zod-helpers", ] } diff --git a/packages/kbn-unified-field-list/src/components/field_item_button/__snapshots__/field_item_button.test.tsx.snap b/packages/kbn-unified-field-list/src/components/field_item_button/__snapshots__/field_item_button.test.tsx.snap index c230cdee040edc..bac19af40c3106 100644 --- a/packages/kbn-unified-field-list/src/components/field_item_button/__snapshots__/field_item_button.test.tsx.snap +++ b/packages/kbn-unified-field-list/src/components/field_item_button/__snapshots__/field_item_button.test.tsx.snap @@ -166,7 +166,20 @@ exports[`UnifiedFieldList renders properly when a conflict f type="conflict" /> } - fieldInfoIcon={} + fieldInfoIcon={ + + } fieldName={ ({ ); - const conflictInfoIcon = field.type === 'conflict' ? : null; + const conflictInfoIcon = + field.type === 'conflict' ? ( + + ) : null; return ( ({ ); } -function FieldConflictInfoIcon() { +function FieldConflictInfoIcon({ + conflictDescriptions, +}: { + conflictDescriptions?: Record; +}) { + const types = conflictDescriptions ? Object.keys(conflictDescriptions) : []; return ( - + ); } diff --git a/packages/kbn-zod-helpers/README.md b/packages/kbn-zod-helpers/README.md new file mode 100644 index 00000000000000..5e622edffefe47 --- /dev/null +++ b/packages/kbn-zod-helpers/README.md @@ -0,0 +1,14 @@ +# Helpers and utilities for Zod + +[Zod](https://zod.dev/) is a schema validation library with static type inference for TypeScript. + +Helpers defined in this package: + +- Can be used in other packages and plugins to make it easier to define schemas with Zod, such as API schemas. +- Are already used in `packages/kbn-openapi-generator`. +- Are already used in `x-pack/plugins/security_solution`. + +When you add some helper code to this package, please make sure that: + +- The code is generic and domain-agnostic (doesn't "know" about any domains such as Security or Observability). +- The code is reusable and there are already a few use cases for it. Try to not generalize prematurely. \ No newline at end of file diff --git a/packages/kbn-zod-helpers/index.ts b/packages/kbn-zod-helpers/index.ts new file mode 100644 index 00000000000000..f1062064dc5cfa --- /dev/null +++ b/packages/kbn-zod-helpers/index.ts @@ -0,0 +1,13 @@ +/* + * 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. + */ + +export * from './src/expect_parse_error'; +export * from './src/expect_parse_success'; +export * from './src/is_valid_date_math'; +export * from './src/required_optional'; +export * from './src/stringify_zod_error'; diff --git a/packages/kbn-zod-helpers/jest.config.js b/packages/kbn-zod-helpers/jest.config.js new file mode 100644 index 00000000000000..773883b1b364d8 --- /dev/null +++ b/packages/kbn-zod-helpers/jest.config.js @@ -0,0 +1,13 @@ +/* + * 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. + */ + +module.exports = { + preset: '@kbn/test', + rootDir: '../..', + roots: ['/packages/kbn-zod-helpers'], +}; diff --git a/packages/kbn-zod-helpers/kibana.jsonc b/packages/kbn-zod-helpers/kibana.jsonc new file mode 100644 index 00000000000000..9f7ad63233d331 --- /dev/null +++ b/packages/kbn-zod-helpers/kibana.jsonc @@ -0,0 +1,6 @@ +{ + "devOnly": false, + "id": "@kbn/zod-helpers", + "owner": "@elastic/security-detection-rule-management", + "type": "shared-common" +} diff --git a/packages/kbn-zod-helpers/package.json b/packages/kbn-zod-helpers/package.json new file mode 100644 index 00000000000000..6d27a7e70f859f --- /dev/null +++ b/packages/kbn-zod-helpers/package.json @@ -0,0 +1,7 @@ +{ + "description": "Zod helpers for Kibana", + "license": "SSPL-1.0 OR Elastic License 2.0", + "name": "@kbn/zod-helpers", + "private": true, + "version": "1.0.0" +} \ No newline at end of file diff --git a/packages/kbn-search-response-warnings/src/components/view_warning_button/index.tsx b/packages/kbn-zod-helpers/src/expect_parse_error.ts similarity index 50% rename from packages/kbn-search-response-warnings/src/components/view_warning_button/index.tsx rename to packages/kbn-zod-helpers/src/expect_parse_error.ts index 4df4d1fa981041..9e5fcb3fd565c9 100644 --- a/packages/kbn-search-response-warnings/src/components/view_warning_button/index.tsx +++ b/packages/kbn-zod-helpers/src/expect_parse_error.ts @@ -6,14 +6,10 @@ * Side Public License, v 1. */ -import React from 'react'; -import type { Props } from './view_warning_button'; +import type { SafeParseError, SafeParseReturnType } from 'zod'; -const Fallback = () =>
; - -const LazyViewWarningButton = React.lazy(() => import('./view_warning_button')); -export const ViewWarningButton = (props: Props) => ( - }> - - -); +export function expectParseError( + result: SafeParseReturnType +): asserts result is SafeParseError { + expect(result.success).toEqual(false); +} diff --git a/x-pack/plugins/security_solution/common/test/zod_helpers.ts b/packages/kbn-zod-helpers/src/expect_parse_success.ts similarity index 50% rename from x-pack/plugins/security_solution/common/test/zod_helpers.ts rename to packages/kbn-zod-helpers/src/expect_parse_success.ts index fd7b8cc8ff3f7f..4fc4a74047933f 100644 --- a/x-pack/plugins/security_solution/common/test/zod_helpers.ts +++ b/packages/kbn-zod-helpers/src/expect_parse_success.ts @@ -1,17 +1,12 @@ /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. + * 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 type { SafeParseError, SafeParseReturnType, SafeParseSuccess } from 'zod'; - -export function expectParseError( - result: SafeParseReturnType -): asserts result is SafeParseError { - expect(result.success).toEqual(false); -} +import type { SafeParseReturnType, SafeParseSuccess } from 'zod'; export function expectParseSuccess( result: SafeParseReturnType diff --git a/packages/kbn-zod-helpers/src/is_valid_date_math.ts b/packages/kbn-zod-helpers/src/is_valid_date_math.ts new file mode 100644 index 00000000000000..8f3bd26f692a70 --- /dev/null +++ b/packages/kbn-zod-helpers/src/is_valid_date_math.ts @@ -0,0 +1,31 @@ +/* + * 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 * as z from 'zod'; +import dateMath from '@kbn/datemath'; + +function validateDateMath(time: string): boolean { + const isValidDateString = !isNaN(Date.parse(time)); + if (isValidDateString) { + return true; + } + const isDateMath = time.trim().startsWith('now'); + if (isDateMath) { + return Boolean(dateMath.parse(time)); + } + return false; +} + +export function isValidDateMath(input: string, ctx: z.RefinementCtx) { + if (!validateDateMath(input)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: 'Failed to parse date-math expression', + }); + } +} diff --git a/packages/kbn-zod-helpers/src/required_optional.ts b/packages/kbn-zod-helpers/src/required_optional.ts new file mode 100644 index 00000000000000..d81d52925286b5 --- /dev/null +++ b/packages/kbn-zod-helpers/src/required_optional.ts @@ -0,0 +1,41 @@ +/* + * 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. + */ + +/** + * Make any optional fields required, but add `| undefined` to their type. + * + * This bit of logic is to force all fields to be accounted for in conversions + * from the internal rule schema to the response schema. Rather than use + * partial, which makes each field optional, we make each field required but + * possibly undefined. The result is that if a field is forgotten in the + * conversion from internal schema to response schema TS will report an error. + * If we just used partial instead, then optional fields can be accidentally + * omitted from the conversion - and any actual values in those fields + * internally will be stripped in the response. + * + * @example + * type A = RequiredOptional<{ a?: string; b: number }>; + * will yield a type of: type A = { a: string | undefined; b: number; } + * + * @note + * We should consider removing this logic altogether from our schemas and use it + * in place with converters whenever needed. + */ +export type RequiredOptional = { [K in keyof T]-?: [T[K]] } extends infer U + ? U extends Record + ? { [K in keyof U]: U[K][0] } + : never + : never; + +/** + * This helper designed to be used with `z.transform` to make all optional fields required. + * + * @param schema Zod schema + * @returns The same schema but with all optional fields required. + */ +export const requiredOptional = (schema: T) => schema as RequiredOptional; diff --git a/packages/kbn-zod-helpers/src/stringify_zod_error.ts b/packages/kbn-zod-helpers/src/stringify_zod_error.ts new file mode 100644 index 00000000000000..b873870f99381c --- /dev/null +++ b/packages/kbn-zod-helpers/src/stringify_zod_error.ts @@ -0,0 +1,21 @@ +/* + * 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 { ZodError } from 'zod'; + +export function stringifyZodError(err: ZodError) { + return err.issues + .map((issue) => { + // If the path is empty, the error is for the root object + if (issue.path.length === 0) { + return issue.message; + } + return `${issue.path.join('.')}: ${issue.message}`; + }) + .join(', '); +} diff --git a/packages/kbn-zod-helpers/tsconfig.json b/packages/kbn-zod-helpers/tsconfig.json new file mode 100644 index 00000000000000..0b3850da21158a --- /dev/null +++ b/packages/kbn-zod-helpers/tsconfig.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "outDir": "target/types", + "types": ["jest", "node"] + }, + "exclude": ["target/**/*"], + "extends": "../../tsconfig.base.json", + "include": ["**/*.ts"], + "kbn_references": [ + "@kbn/datemath", + ] +} diff --git a/scripts/snapshot_plugin_types.js b/scripts/snapshot_plugin_types.js index 151d9b96185c05..f77c73f3904322 100644 --- a/scripts/snapshot_plugin_types.js +++ b/scripts/snapshot_plugin_types.js @@ -7,4 +7,31 @@ */ require('../src/setup_node_env'); -require('../src/dev/so_migration/so_migration_cli'); + +var command = process.argv[2]; + +switch (command) { + case 'snapshot': + require('../src/dev/so_migration/so_migration_snapshot_cli'); + break; + case 'compare': + require('../src/dev/so_migration/so_migration_compare_cli'); + break; + default: + printHelp(); + break; +} + +function printHelp() { + var scriptName = process.argv[1].replace(/^.*scripts\//, 'scripts/'); + + console.log(` + Usage: node ${scriptName} + + Commands: + snapshot - Create a snapshot of the current Saved Object types + compare - Compare two snapshots to reveal changes in Saved Object types + `); + + process.exit(0); +} diff --git a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts index 559bbfb19a4154..dc583d97190a9f 100644 --- a/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts +++ b/src/core/server/integration_tests/saved_objects/migrations/group3/actions/actions.test.ts @@ -5,27 +5,2062 @@ * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ -import { createTestServers } from '@kbn/core-test-helpers-kbn-server'; -import { MIGRATION_CLIENT_OPTIONS } from '@kbn/core-saved-objects-migration-server-internal'; -import { runActionTestSuite } from './actions_test_suite'; + +import Path from 'path'; +import * as Either from 'fp-ts/lib/Either'; +import * as Option from 'fp-ts/lib/Option'; +import { errors } from '@elastic/elasticsearch'; +import type { TaskEither } from 'fp-ts/lib/TaskEither'; +import type { SavedObjectsRawDoc } from '@kbn/core-saved-objects-server'; +import type { ElasticsearchClient } from '@kbn/core-elasticsearch-server'; +import { elasticsearchServiceMock } from '@kbn/core-elasticsearch-server-mocks'; +import { createTestServers, type TestElasticsearchUtils } from '@kbn/core-test-helpers-kbn-server'; +import { + bulkOverwriteTransformedDocuments, + closePit, + createIndex, + openPit, + type OpenPitResponse, + reindex, + readWithPit, + type EsResponseTooLargeError, + type ReadWithPit, + setWriteBlock, + updateAliases, + waitForReindexTask, + type ReindexResponse, + waitForPickupUpdatedMappingsTask, + pickupUpdatedMappings, + type UpdateByQueryResponse, + updateAndPickupMappings, + type UpdateAndPickupMappingsResponse, + updateMappings, + removeWriteBlock, + transformDocs, + waitForIndexStatus, + initAction, + cloneIndex, + type DocumentsTransformFailed, + type DocumentsTransformSuccess, + MIGRATION_CLIENT_OPTIONS, + createBulkIndexOperationTuple, +} from '@kbn/core-saved-objects-migration-server-internal'; const { startES } = createTestServers({ adjustTimeout: (t: number) => jest.setTimeout(t), settings: { es: { license: 'basic', + dataArchive: Path.resolve(__dirname, '../../archives/7.7.2_xpack_100k_obj.zip'), esArgs: ['http.max_content_length=10Kb'], }, }, }); +let esServer: TestElasticsearchUtils; describe('migration actions', () => { - runActionTestSuite({ - startEs: async () => { - const esServer = await startES(); - const client = esServer.es.getClient().child(MIGRATION_CLIENT_OPTIONS); - return { esServer, client }; - }, - environment: 'traditional', + let client: ElasticsearchClient; + let esCapabilities: ReturnType; + + beforeAll(async () => { + esServer = await startES(); + client = esServer.es.getClient().child(MIGRATION_CLIENT_OPTIONS); + esCapabilities = elasticsearchServiceMock.createCapabilities(); + + // Create test fixture data: + await createIndex({ + client, + indexName: 'existing_index_with_docs', + aliases: ['existing_index_with_docs_alias'], + esCapabilities, + mappings: { + dynamic: true, + properties: { + someProperty: { + type: 'integer', + }, + }, + _meta: { + migrationMappingPropertyHashes: { + references: '7997cf5a56cc02bdc9c93361bde732b0', + }, + }, + }, + })(); + const docs = [ + { _source: { title: 'doc 1' } }, + { _source: { title: 'doc 2' } }, + { _source: { title: 'doc 3' } }, + { _source: { title: 'saved object 4', type: 'another_unused_type' } }, + { _source: { title: 'f-agent-event 5', type: 'f_agent_event' } }, + { _source: { title: new Array(1000).fill('a').join(), type: 'large' } }, // "large" saved object + ] as unknown as SavedObjectsRawDoc[]; + await bulkOverwriteTransformedDocuments({ + client, + index: 'existing_index_with_docs', + operations: docs.map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + })(); + + await createIndex({ + client, + indexName: 'existing_index_2', + mappings: { properties: {} }, + esCapabilities, + })(); + await createIndex({ + client, + indexName: 'existing_index_with_write_block', + mappings: { properties: {} }, + esCapabilities, + })(); + await bulkOverwriteTransformedDocuments({ + client, + index: 'existing_index_with_write_block', + operations: docs.map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + })(); + await setWriteBlock({ client, index: 'existing_index_with_write_block' })(); + await updateAliases({ + client, + aliasActions: [{ add: { index: 'existing_index_2', alias: 'existing_index_2_alias' } }], + })(); + }); + + afterAll(async () => { + await esServer.stop(); + }); + + describe('initAction', () => { + afterAll(async () => { + await client.cluster.putSettings({ + body: { + persistent: { + // Reset persistent test settings + cluster: { routing: { allocation: { enable: null } } }, + }, + }, + }); + }); + it('resolves right empty record if no indices were found', async () => { + expect.assertions(1); + const task = initAction({ client, indices: ['no_such_index'] }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": Object {}, + } + `); + }); + it('resolves right record with found indices', async () => { + expect.assertions(1); + const res = (await initAction({ + client, + indices: ['no_such_index', 'existing_index_with_docs'], + })()) as Either.Right; + + expect(res.right).toEqual( + expect.objectContaining({ + existing_index_with_docs: { + aliases: { + existing_index_with_docs_alias: {}, + }, + mappings: expect.anything(), + settings: expect.anything(), + }, + }) + ); + }); + it('includes the _meta data of the indices in the response', async () => { + expect.assertions(1); + const res = (await initAction({ + client, + indices: ['existing_index_with_docs'], + })()) as Either.Right; + + expect(res.right).toEqual( + expect.objectContaining({ + existing_index_with_docs: { + aliases: { + existing_index_with_docs_alias: {}, + }, + mappings: { + // FIXME https://github.com/elastic/elasticsearch-js/issues/1796 + dynamic: 'true', + properties: expect.anything(), + _meta: { + migrationMappingPropertyHashes: { + references: '7997cf5a56cc02bdc9c93361bde732b0', + }, + }, + }, + settings: expect.anything(), + }, + }) + ); + }); + it('resolves left when cluster.routing.allocation.enabled is incompatible', async () => { + expect.assertions(3); + await client.cluster.putSettings({ + body: { + persistent: { + // Disable all routing allocation + cluster: { routing: { allocation: { enable: 'none' } } }, + }, + }, + }); + const task = initAction({ + client, + indices: ['existing_index_with_docs'], + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "incompatible_cluster_routing_allocation", + }, + } + `); + await client.cluster.putSettings({ + body: { + persistent: { + // Allow routing to existing primaries only + cluster: { routing: { allocation: { enable: 'primaries' } } }, + }, + }, + }); + const task2 = initAction({ + client, + indices: ['existing_index_with_docs'], + }); + await expect(task2()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "incompatible_cluster_routing_allocation", + }, + } + `); + await client.cluster.putSettings({ + body: { + persistent: { + // Allow routing to new primaries only + cluster: { routing: { allocation: { enable: 'new_primaries' } } }, + }, + }, + }); + const task3 = initAction({ + client, + indices: ['existing_index_with_docs'], + }); + await expect(task3()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "incompatible_cluster_routing_allocation", + }, + } + `); + }); + it('resolves right when cluster.routing.allocation.enabled=all', async () => { + expect.assertions(1); + await client.cluster.putSettings({ + body: { + persistent: { + cluster: { routing: { allocation: { enable: 'all' } } }, + }, + }, + }); + const task = initAction({ + client, + indices: ['existing_index_with_docs'], + }); + const result = await task(); + expect(Either.isRight(result)).toBe(true); + }); + }); + + describe('setWriteBlock', () => { + beforeAll(async () => { + await createIndex({ + client, + indexName: 'new_index_without_write_block', + mappings: { properties: {} }, + esCapabilities, + })(); + }); + it('resolves right when setting the write block succeeds', async () => { + expect.assertions(1); + const task = setWriteBlock({ client, index: 'new_index_without_write_block' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "set_write_block_succeeded", + } + `); + }); + it('resolves right when setting a write block on an index that already has one', async () => { + expect.assertions(1); + const task = setWriteBlock({ client, index: 'existing_index_with_write_block' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "set_write_block_succeeded", + } + `); + }); + it('once resolved, prevents further writes to the index', async () => { + expect.assertions(1); + const task = setWriteBlock({ client, index: 'new_index_without_write_block' }); + await task(); + const sourceDocs = [ + { _source: { title: 'doc 1' } }, + { _source: { title: 'doc 2' } }, + { _source: { title: 'doc 3' } }, + { _source: { title: 'doc 4' } }, + ] as unknown as SavedObjectsRawDoc[]; + + const res = (await bulkOverwriteTransformedDocuments({ + client, + index: 'new_index_without_write_block', + operations: sourceDocs.map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + })()) as Either.Left; + + expect(res.left).toEqual({ + type: 'target_index_had_write_block', + }); + }); + it('resolves left index_not_found_exception when the index does not exist', async () => { + expect.assertions(1); + const task = setWriteBlock({ client, index: 'no_such_index' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "index": "no_such_index", + "type": "index_not_found_exception", + }, + } + `); + }); + }); + + describe('removeWriteBlock', () => { + beforeAll(async () => { + await createIndex({ + client, + indexName: 'existing_index_without_write_block_2', + mappings: { properties: {} }, + esCapabilities, + })(); + await createIndex({ + client, + indexName: 'existing_index_with_write_block_2', + mappings: { properties: {} }, + esCapabilities, + })(); + await setWriteBlock({ client, index: 'existing_index_with_write_block_2' })(); + }); + it('resolves right if successful when an index already has a write block', async () => { + expect.assertions(1); + const task = removeWriteBlock({ client, index: 'existing_index_with_write_block_2' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "remove_write_block_succeeded", + } + `); + }); + it('resolves right if successful when an index does not have a write block', async () => { + expect.assertions(1); + const task = removeWriteBlock({ client, index: 'existing_index_without_write_block_2' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "remove_write_block_succeeded", + } + `); + }); + it('rejects if there is a non-retryable error', async () => { + expect.assertions(1); + const task = removeWriteBlock({ client, index: 'no_such_index' }); + await expect(task()).rejects.toThrow('index_not_found_exception'); + }); + }); + + describe('waitForIndexStatus', () => { + afterEach(async () => { + try { + await client.indices.delete({ index: 'red_then_yellow_index' }); + await client.indices.delete({ index: 'red_index' }); + } catch (e) { + /** ignore */ + } + }); + it('resolves right after waiting for an index status to be yellow if the index already existed', async () => { + // Create a red index + await client.indices.create( + { + index: 'red_then_yellow_index', + timeout: '5s', + body: { + mappings: { properties: {} }, + settings: { + // Allocate 1 replica so that this index stays yellow + number_of_replicas: '1', + // Disable all shard allocation so that the index status is red + routing: { allocation: { enable: 'none' } }, + }, + }, + }, + { maxRetries: 0 /** handle retry ourselves for now */ } + ); + + // Start tracking the index status + const indexStatusPromise = waitForIndexStatus({ + client, + index: 'red_then_yellow_index', + status: 'yellow', + })(); + + const redStatusResponse = await client.cluster.health({ index: 'red_then_yellow_index' }); + expect(redStatusResponse.status).toBe('red'); + + client.indices.putSettings({ + index: 'red_then_yellow_index', + body: { + // Enable all shard allocation so that the index status turns yellow + routing: { allocation: { enable: 'all' } }, + }, + }); + + await indexStatusPromise; + // Assert that the promise didn't resolve before the index became yellow + + const yellowStatusResponse = await client.cluster.health({ index: 'red_then_yellow_index' }); + expect(yellowStatusResponse.status).toBe('yellow'); + }); + it('resolves left with "index_not_yellow_timeout" after waiting for an index status to be yellow timeout', async () => { + // Create a red index + await client.indices + .create({ + index: 'red_index', + timeout: '5s', + body: { + mappings: { properties: {} }, + settings: { + // Allocate no replicas so that this index stays red + number_of_replicas: '0', + // Disable all shard allocation so that the index status is red + index: { routing: { allocation: { enable: 'none' } } }, + }, + }, + }) + .catch((e) => {}); + // try to wait for index status yellow: + const task = waitForIndexStatus({ + client, + index: 'red_index', + timeout: '1s', + status: 'yellow', + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "message": "[index_not_yellow_timeout] Timeout waiting for the status of the [red_index] index to become 'yellow'", + "type": "index_not_yellow_timeout", + }, + } + `); + }); + + it('resolves left with "index_not_green_timeout" after waiting for an index status to be green timeout', async () => { + // Create a yellow index + await client.indices + .create({ + index: 'yellow_index', + timeout: '5s', + body: { + mappings: { properties: {} }, + settings: { + // Allocate no replicas so that this index stays yellow + number_of_replicas: '0', + }, + }, + }) + .catch((e) => {}); + // try to wait for index status yellow: + const task = waitForIndexStatus({ + client, + index: 'red_index', + timeout: '1s', + status: 'green', + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "message": "[index_not_green_timeout] Timeout waiting for the status of the [red_index] index to become 'green'", + "type": "index_not_green_timeout", + }, + } + `); + }); + }); + + describe('cloneIndex', () => { + afterAll(async () => { + try { + // Restore the default setting of 1000 shards per node + await client.cluster.putSettings({ + persistent: { cluster: { max_shards_per_node: null } }, + }); + await client.indices.delete({ index: 'clone_*' }); + } catch (e) { + /** ignore */ + } + }); + it('resolves right if cloning into a new target index', async () => { + const task = cloneIndex({ + client, + source: 'existing_index_with_write_block', + target: 'clone_target_1', + esCapabilities, + }); + expect.assertions(3); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": Object { + "acknowledged": true, + "shardsAcknowledged": true, + }, + } + `); + const { clone_target_1: cloneTarget1 } = await client.indices.getSettings({ + index: 'clone_target_1', + }); + // @ts-expect-error https://github.com/elastic/elasticsearch/issues/89381 + expect(cloneTarget1.settings?.index.mapping?.total_fields.limit).toBe('1500'); + expect(cloneTarget1.settings?.blocks?.write).toBeUndefined(); + }); + it('resolves right if clone target already existed after waiting for index status to be green ', async () => { + expect.assertions(2); + + // Create a red index that we later turn into green + await client.indices + .create({ + index: 'clone_red_then_green_index', + timeout: '5s', + body: { + mappings: { properties: {} }, + settings: { + // Allocate 1 replica so that this index can go to green + number_of_replicas: '0', + // Disable all shard allocation so that the index status is red + index: { routing: { allocation: { enable: 'none' } } }, + }, + }, + }) + .catch((e) => {}); + + // Call clone even though the index already exists + const cloneIndexPromise = cloneIndex({ + client, + source: 'existing_index_with_write_block', + target: 'clone_red_then_green_index', + esCapabilities, + })(); + + let indexGreen = false; + setTimeout(() => { + client.indices.putSettings({ + index: 'clone_red_then_green_index', + body: { + // Enable all shard allocation so that the index status goes green + routing: { allocation: { enable: 'all' } }, + }, + }); + indexGreen = true; + }, 10); + + await cloneIndexPromise.then((res) => { + // Assert that the promise didn't resolve before the index became green + expect(indexGreen).toBe(true); + expect(res).toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": Object { + "acknowledged": true, + "shardsAcknowledged": true, + }, + } + `); + }); + }); + it('resolves left with a index_not_green_timeout if clone target already exists but takes longer than the specified timeout before turning green', async () => { + // Create a red index + await client.indices + .create({ + index: 'clone_red_index', + timeout: '5s', + body: { + mappings: { properties: {} }, + settings: { + // Allocate 1 replica so that this index stays yellow + number_of_replicas: '1', + // Disable all shard allocation so that the index status is red + index: { routing: { allocation: { enable: 'none' } } }, + }, + }, + }) + .catch((e) => {}); + + // Call clone even though the index already exists + let cloneIndexPromise = cloneIndex({ + client, + source: 'existing_index_with_write_block', + target: 'clone_red_index', + timeout: '1s', + esCapabilities, + })(); + + await expect(cloneIndexPromise).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "message": "[index_not_green_timeout] Timeout waiting for the status of the [clone_red_index] index to become 'green'", + "type": "index_not_green_timeout", + }, + } + `); + + // Now make the index yellow and repeat + + await client.indices.putSettings({ + index: 'clone_red_index', + body: { + // Enable all shard allocation so that the index status goes yellow + routing: { allocation: { enable: 'all' } }, + }, + }); + + // Call clone even though the index already exists + cloneIndexPromise = cloneIndex({ + client, + source: 'existing_index_with_write_block', + target: 'clone_red_index', + timeout: '1s', + esCapabilities, + })(); + + await expect(cloneIndexPromise).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "message": "[index_not_green_timeout] Timeout waiting for the status of the [clone_red_index] index to become 'green'", + "type": "index_not_green_timeout", + }, + } + `); + + // Now make the index green and it should succeed + + await client.indices.putSettings({ + index: 'clone_red_index', + body: { + // Set zero replicas so status goes green + number_of_replicas: 0, + }, + }); + + // Call clone even though the index already exists + cloneIndexPromise = cloneIndex({ + client, + source: 'existing_index_with_write_block', + target: 'clone_red_index', + timeout: '30s', + esCapabilities, + })(); + + await expect(cloneIndexPromise).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": Object { + "acknowledged": true, + "shardsAcknowledged": true, + }, + } + `); + }); + it('resolves left index_not_found_exception if the source index does not exist', async () => { + expect.assertions(1); + const task = cloneIndex({ + client, + source: 'no_such_index', + target: 'clone_target_3', + esCapabilities, + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "index": "no_such_index", + "type": "index_not_found_exception", + }, + } + `); + }); + it('resolves left cluster_shard_limit_exceeded when the action would exceed the maximum normal open shards', async () => { + // Set the max shards per node really low so that any new index that's created would exceed the maximum open shards for this cluster + await client.cluster.putSettings({ persistent: { cluster: { max_shards_per_node: 1 } } }); + const cloneIndexPromise = cloneIndex({ + client, + source: 'existing_index_with_write_block', + target: 'clone_target_4', + esCapabilities, + })(); + await expect(cloneIndexPromise).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "cluster_shard_limit_exceeded", + }, + } + `); + }); + }); + + // Reindex doesn't return any errors on it's own, so we have to test + // together with waitForReindexTask + describe('reindex & waitForReindexTask', () => { + it('resolves right when reindex succeeds without reindex script', async () => { + const res = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'reindex_target', + reindexScript: Option.none, + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + const task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "reindex_succeeded", + } + `); + + const results = await client.search({ index: 'reindex_target', size: 1000 }); + expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) + .toMatchInlineSnapshot(` + Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a", + "doc 1", + "doc 2", + "doc 3", + "f-agent-event 5", + "saved object 4", + ] + `); + }); + it('resolves right and excludes all documents not matching the excludeOnUpgradeQuery', async () => { + const res = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'reindex_target_excluded_docs', + reindexScript: Option.none, + requireAlias: false, + excludeOnUpgradeQuery: { + bool: { + must_not: ['f_agent_event', 'another_unused_type'].map((type) => ({ + term: { type }, + })), + }, + }, + batchSize: 1000, + })()) as Either.Right; + const task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "reindex_succeeded", + } + `); + + const results = await client.search({ index: 'reindex_target_excluded_docs', size: 1000 }); + expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) + .toMatchInlineSnapshot(` + Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a", + "doc 1", + "doc 2", + "doc 3", + ] + `); + }); + it('resolves right when reindex succeeds with reindex script', async () => { + expect.assertions(2); + const res = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'reindex_target_2', + reindexScript: Option.some(`ctx._source.title = ctx._source.title + '_updated'`), + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + const task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "reindex_succeeded", + } + `); + + const results = await client.search({ index: 'reindex_target_2', size: 1000 }); + expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) + .toMatchInlineSnapshot(` + Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a_updated", + "doc 1_updated", + "doc 2_updated", + "doc 3_updated", + "f-agent-event 5_updated", + "saved object 4_updated", + ] + `); + }); + it('resolves right, ignores version conflicts and does not update existing docs when reindex multiple times', async () => { + expect.assertions(3); + // Reindex with a script + let res = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'reindex_target_3', + reindexScript: Option.some(`ctx._source.title = ctx._source.title + '_updated'`), + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + let task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "reindex_succeeded", + } + `); + + // reindex without a script + res = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'reindex_target_3', + reindexScript: Option.none, + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "reindex_succeeded", + } + `); + + // Assert that documents weren't overridden by the second, unscripted reindex + const results = await client.search({ index: 'reindex_target_3', size: 1000 }); + expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) + .toMatchInlineSnapshot(` + Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a_updated", + "doc 1_updated", + "doc 2_updated", + "doc 3_updated", + "f-agent-event 5_updated", + "saved object 4_updated", + ] + `); + }); + it('resolves right and proceeds to add missing documents if there are some existing docs conflicts', async () => { + expect.assertions(2); + // Simulate a reindex that only adds some of the documents from the + // source index into the target index + await createIndex({ + client, + indexName: 'reindex_target_4', + mappings: { properties: {} }, + esCapabilities, + })(); + const response = await client.search({ index: 'existing_index_with_docs', size: 1000 }); + const sourceDocs = (response.hits?.hits as SavedObjectsRawDoc[]) + .slice(0, 2) + .map(({ _id, _source }) => ({ + _id, + _source, + })); + await bulkOverwriteTransformedDocuments({ + client, + index: 'reindex_target_4', + operations: sourceDocs.map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + })(); + + // Now do a real reindex + const res = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'reindex_target_4', + reindexScript: Option.some(`ctx._source.title = ctx._source.title + '_updated'`), + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + const task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "reindex_succeeded", + } + `); + // Assert that existing documents weren't overridden, but that missing + // documents were added by the reindex + const results = await client.search({ index: 'reindex_target_4', size: 1000 }); + expect((results.hits?.hits as SavedObjectsRawDoc[]).map((doc) => doc._source.title).sort()) + .toMatchInlineSnapshot(` + Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a_updated", + "doc 1", + "doc 2", + "doc 3_updated", + "f-agent-event 5_updated", + "saved object 4_updated", + ] + `); + }); + it('resolves left incompatible_mapping_exception if all reindex failures are due to a strict_dynamic_mapping_exception', async () => { + expect.assertions(1); + // Simulates one instance having completed the UPDATE_TARGET_MAPPINGS + // step which makes the mappings incompatible with outdated documents. + // If another instance then tries a reindex it will get a + // strict_dynamic_mapping_exception even if the documents already exist + // and should ignore this error. + + // Create an index with incompatible mappings + await createIndex({ + client, + indexName: 'reindex_target_5', + mappings: { + dynamic: 'strict', + properties: { + /** no title field */ + }, + }, + esCapabilities, + })(); + + const { + right: { taskId: reindexTaskId }, + } = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'reindex_target_5', + reindexScript: Option.none, + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + const task = waitForReindexTask({ client, taskId: reindexTaskId, timeout: '10s' }); + + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "incompatible_mapping_exception", + }, + } + `); + }); + it('resolves left incompatible_mapping_exception if all reindex failures are due to a mapper_parsing_exception', async () => { + expect.assertions(1); + // Simulates one instance having completed the UPDATE_TARGET_MAPPINGS + // step which makes the mappings incompatible with outdated documents. + // If another instance then tries a reindex it will get a + // strict_dynamic_mapping_exception even if the documents already exist + // and should ignore this error. + + // Create an index with incompatible mappings + await createIndex({ + client, + indexName: 'reindex_target_6', + mappings: { + dynamic: false, + properties: { title: { type: 'integer' } }, // integer is incompatible with string title + }, + esCapabilities, + })(); + + const { + right: { taskId: reindexTaskId }, + } = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'reindex_target_6', + reindexScript: Option.none, + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + const task = waitForReindexTask({ client, taskId: reindexTaskId, timeout: '10s' }); + + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "incompatible_mapping_exception", + }, + } + `); + }); + it('resolves left index_not_found_exception if source index does not exist', async () => { + expect.assertions(1); + const res = (await reindex({ + client, + sourceIndex: 'no_such_index', + targetIndex: 'reindex_target', + reindexScript: Option.none, + requireAlias: false, + excludeOnUpgradeQuery: { + match_all: {}, + }, + batchSize: 1000, + })()) as Either.Right; + const task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "index": "no_such_index", + "type": "index_not_found_exception", + }, + } + `); + }); + it('resolves left target_index_had_write_block if all failures are due to a write block', async () => { + expect.assertions(1); + const res = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'existing_index_with_write_block', + reindexScript: Option.none, + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + + const task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "target_index_had_write_block", + }, + } + `); + }); + it('resolves left if requireAlias=true and the target is not an alias', async () => { + expect.assertions(1); + const res = (await reindex({ + client, + sourceIndex: 'existing_index_with_docs', + targetIndex: 'existing_index_with_write_block', + reindexScript: Option.none, + requireAlias: true, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + + const task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '10s' }); + + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "index": "existing_index_with_write_block", + "type": "index_not_found_exception", + }, + } + `); + }); + it('resolves left wait_for_task_completion_timeout when the task does not finish within the timeout', async () => { + await waitForIndexStatus({ + client, + index: '.kibana_1', + status: 'yellow', + })(); + + const res = (await reindex({ + client, + sourceIndex: '.kibana_1', + targetIndex: 'reindex_target', + reindexScript: Option.none, + requireAlias: false, + excludeOnUpgradeQuery: { match_all: {} }, + batchSize: 1000, + })()) as Either.Right; + + const task = waitForReindexTask({ client, taskId: res.right.taskId, timeout: '0s' }); + + await expect(task()).resolves.toMatchObject({ + _tag: 'Left', + left: { + error: expect.any(errors.ResponseError), + message: expect.stringContaining('[timeout_exception]'), + type: 'wait_for_task_completion_timeout', + }, + }); + }); + }); + + describe('openPit', () => { + it('opens PointInTime for an index', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + expect(pitResponse.right.pitId).toEqual(expect.any(String)); + + const searchResponse = await client.search({ + body: { + pit: { id: pitResponse.right.pitId }, + }, + }); + + await expect(searchResponse.hits.hits.length).toBeGreaterThan(0); + }); + it('rejects if index does not exist', async () => { + const openPitTask = openPit({ client, index: 'no_such_index' }); + await expect(openPitTask()).rejects.toThrow('index_not_found_exception'); + }); + }); + + describe('readWithPit', () => { + it('requests documents from an index using given PIT', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + const readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { match_all: {} }, + batchSize: 1000, + searchAfter: undefined, + }); + const docsResponse = (await readWithPitTask()) as Either.Right; + + await expect(docsResponse.right.outdatedDocuments.length).toBe(6); + }); + + it('requests the batchSize of documents from an index', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + const readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { match_all: {} }, + batchSize: 3, + searchAfter: undefined, + }); + const docsResponse = (await readWithPitTask()) as Either.Right; + + await expect(docsResponse.right.outdatedDocuments.length).toBe(3); + }); + + it('it excludes documents not matching the provided "query"', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + const readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { + bool: { + must_not: [ + { + term: { + type: 'f_agent_event', + }, + }, + { + term: { + type: 'another_unused_type', + }, + }, + ], + }, + }, + batchSize: 1000, + searchAfter: undefined, + }); + + const docsResponse = (await readWithPitTask()) as Either.Right; + + expect(docsResponse.right.outdatedDocuments.map((doc) => doc._source.title).sort()) + .toMatchInlineSnapshot(` + Array [ + "a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a,a", + "doc 1", + "doc 2", + "doc 3", + ] + `); + }); + + it('only returns documents that match the provided "query"', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + const readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { + match: { title: { query: 'doc' } }, + }, + batchSize: 1000, + searchAfter: undefined, + }); + + const docsResponse = (await readWithPitTask()) as Either.Right; + + expect(docsResponse.right.outdatedDocuments.map((doc) => doc._source.title).sort()) + .toMatchInlineSnapshot(` + Array [ + "doc 1", + "doc 2", + "doc 3", + ] + `); + }); + + it('returns docs with _seq_no and _primary_term when specified', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + const readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { + match: { title: { query: 'doc' } }, + }, + batchSize: 1000, + searchAfter: undefined, + seqNoPrimaryTerm: true, + }); + + const docsResponse = (await readWithPitTask()) as Either.Right; + + expect(docsResponse.right.outdatedDocuments).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + _seq_no: expect.any(Number), + _primary_term: expect.any(Number), + }), + ]) + ); + }); + + it('does not return docs with _seq_no and _primary_term if not specified', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + const readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { + match: { title: { query: 'doc' } }, + }, + batchSize: 1000, + searchAfter: undefined, + }); + + const docsResponse = (await readWithPitTask()) as Either.Right; + + expect(docsResponse.right.outdatedDocuments).toEqual( + expect.arrayContaining([ + expect.not.objectContaining({ + _seq_no: expect.any(Number), + _primary_term: expect.any(Number), + }), + ]) + ); + }); + + it('returns a left es_response_too_large error when a read batch exceeds the maxResponseSize', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + let readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { match_all: {} }, + batchSize: 1, // small batch size so we don't exceed the maxResponseSize + searchAfter: undefined, + maxResponseSizeBytes: 500, // set a small size to force the error + }); + const rightResponse = (await readWithPitTask()) as Either.Right; + + await expect(Either.isRight(rightResponse)).toBe(true); + + readWithPitTask = readWithPit({ + client, + pitId: pitResponse.right.pitId, + query: { match_all: {} }, + batchSize: 10, // a bigger batch will exceed the maxResponseSize + searchAfter: undefined, + maxResponseSizeBytes: 500, // set a small size to force the error + }); + const leftResponse = (await readWithPitTask()) as Either.Left; + + expect(leftResponse.left.type).toBe('es_response_too_large'); + // ES response contains a field that indicates how long it took ES to get the response, e.g.: "took": 7 + // if ES takes more than 9ms, the payload will be 1 byte bigger. + // see https://github.com/elastic/kibana/issues/160994 + // Thus, the statements below account for response times up to 99ms + expect(leftResponse.left.contentLength).toBeGreaterThanOrEqual(3184); + expect(leftResponse.left.contentLength).toBeLessThanOrEqual(3185); + }); + + it('rejects if PIT does not exist', async () => { + const readWithPitTask = readWithPit({ + client, + pitId: 'no_such_pit', + query: { match_all: {} }, + batchSize: 1000, + searchAfter: undefined, + }); + await expect(readWithPitTask()).rejects.toThrow('illegal_argument_exception'); + }); + }); + + describe('closePit', () => { + it('closes PointInTime', async () => { + const openPitTask = openPit({ client, index: 'existing_index_with_docs' }); + const pitResponse = (await openPitTask()) as Either.Right; + + const pitId = pitResponse.right.pitId; + await closePit({ client, pitId })(); + + const searchTask = client.search({ + body: { + pit: { id: pitId }, + }, + }); + + await expect(searchTask).rejects.toThrow('search_phase_execution_exception'); + }); + + it('rejects if PIT does not exist', async () => { + const closePitTask = closePit({ client, pitId: 'no_such_pit' }); + await expect(closePitTask()).rejects.toThrow('illegal_argument_exception'); + }); + }); + + describe('transformDocs', () => { + it('applies "transformRawDocs" and returns the transformed documents', async () => { + const originalDocs = [ + { _id: 'foo:1', _source: { type: 'dashboard', value: 1 } }, + { _id: 'foo:2', _source: { type: 'dashboard', value: 2 } }, + ]; + + function innerTransformRawDocs( + docs: SavedObjectsRawDoc[] + ): TaskEither { + return async () => { + const processedDocs: SavedObjectsRawDoc[] = []; + for (const doc of docs) { + doc._source.value += 1; + processedDocs.push(doc); + } + return Either.right({ processedDocs }); + }; + } + + const transformTask = transformDocs({ + transformRawDocs: innerTransformRawDocs, + outdatedDocuments: originalDocs, + }); + + const resultsWithProcessDocs = ( + (await transformTask()) as Either.Right + ).right.processedDocs; + expect(resultsWithProcessDocs.length).toEqual(2); + const foo2 = resultsWithProcessDocs.find((h) => h._id === 'foo:2'); + expect(foo2?._source?.value).toBe(3); + }); + }); + + describe('waitForPickupUpdatedMappingsTask', () => { + it('rejects if there are failures', async () => { + const res = (await pickupUpdatedMappings( + client, + 'existing_index_with_write_block', + 1000 + )()) as Either.Right; + + const task = waitForPickupUpdatedMappingsTask({ + client, + taskId: res.right.taskId, + timeout: '10s', + }); + + // We can't do a snapshot match because the response includes an index + // id which ES assigns dynamically + await expect(task()).rejects.toMatchObject({ + message: + /pickupUpdatedMappings task failed with the following failures:\n\[\{\"index\":\"existing_index_with_write_block\"/, + }); + }); + it('rejects if there is an error', async () => { + const res = (await pickupUpdatedMappings( + client, + 'no_such_index', + 1000 + )()) as Either.Right; + + const task = waitForPickupUpdatedMappingsTask({ + client, + taskId: res.right.taskId, + timeout: '10s', + }); + + await expect(task()).rejects.toThrow('index_not_found_exception'); + }); + + it('resolves left wait_for_task_completion_timeout when the task does not complete within the timeout', async () => { + const res = (await pickupUpdatedMappings( + client, + '.kibana_1', + 1000 + )()) as Either.Right; + + const task = waitForPickupUpdatedMappingsTask({ + client, + taskId: res.right.taskId, + timeout: '0s', + }); + + await expect(task()).resolves.toMatchObject({ + _tag: 'Left', + left: { + error: expect.any(errors.ResponseError), + message: expect.stringContaining('[timeout_exception]'), + type: 'wait_for_task_completion_timeout', + }, + }); + }); + it('resolves right when successful', async () => { + const res = (await pickupUpdatedMappings( + client, + 'existing_index_with_docs', + 1000 + )()) as Either.Right; + + const task = waitForPickupUpdatedMappingsTask({ + client, + taskId: res.right.taskId, + timeout: '10s', + }); + + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "pickup_updated_mappings_succeeded", + } + `); + }); + }); + + describe('updateAndPickupMappings', () => { + it('resolves right when mappings were updated and picked up', async () => { + // Create an index without any mappings and insert documents into it + await createIndex({ + client, + indexName: 'existing_index_without_mappings', + mappings: { + dynamic: false, + properties: {}, + }, + esCapabilities, + })(); + const sourceDocs = [ + { _source: { title: 'doc 1' } }, + { _source: { title: 'doc 2' } }, + { _source: { title: 'doc 3' } }, + { _source: { title: 'doc 4' } }, + ] as unknown as SavedObjectsRawDoc[]; + await bulkOverwriteTransformedDocuments({ + client, + index: 'existing_index_without_mappings', + operations: sourceDocs.map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + })(); + + // Assert that we can't search over the unmapped fields of the document + + const originalSearchResults = await client.search({ + index: 'existing_index_without_mappings', + size: 1000, + query: { + match: { title: { query: 'doc' } }, + }, + }); + expect(originalSearchResults.hits?.hits.length).toBe(0); + + // Update and pickup mappings so that the title field is searchable + const res = await updateAndPickupMappings({ + client, + index: 'existing_index_without_mappings', + mappings: { + properties: { + title: { type: 'text' }, + }, + }, + batchSize: 1000, + })(); + expect(Either.isRight(res)).toBe(true); + const taskId = (res as Either.Right).right.taskId; + await waitForPickupUpdatedMappingsTask({ client, taskId, timeout: '60s' })(); + + // Repeat the search expecting to be able to find the existing documents + const pickedUpSearchResults = await client.search({ + index: 'existing_index_without_mappings', + size: 1000, + query: { + match: { title: { query: 'doc' } }, + }, + }); + expect(pickedUpSearchResults.hits?.hits.length).toBe(4); + }); + }); + + describe('updateMappings', () => { + it('rejects if ES throws an error', async () => { + const task = updateMappings({ + client, + index: 'no_such_index', + mappings: { + properties: { + created_at: { + type: 'date', + }, + }, + _meta: { + migrationMappingPropertyHashes: { + references: 'updateda56cc02bdc9c93361bupdated', + newReferences: 'fooBarHashMd509387420934879300d9', + }, + }, + }, + })(); + + await expect(task).rejects.toThrow('index_not_found_exception'); + }); + + it('resolves left when the mappings are incompatible', async () => { + const res = await updateMappings({ + client, + index: 'existing_index_with_docs', + mappings: { + properties: { + someProperty: { + type: 'date', // attempt to change an existing field's type in an incompatible fashion + }, + }, + _meta: { + migrationMappingPropertyHashes: { + references: 'updateda56cc02bdc9c93361bupdated', + newReferences: 'fooBarHashMd509387420934879300d9', + }, + }, + }, + })(); + + expect(Either.isLeft(res)).toBe(true); + expect(res).toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "incompatible_mapping_exception", + }, + } + `); + }); + + it('resolves right when mappings are correctly updated', async () => { + const res = await updateMappings({ + client, + index: 'existing_index_with_docs', + mappings: { + properties: { + created_at: { + type: 'date', + }, + }, + _meta: { + migrationMappingPropertyHashes: { + references: 'updateda56cc02bdc9c93361bupdated', + newReferences: 'fooBarHashMd509387420934879300d9', + }, + }, + }, + })(); + + expect(Either.isRight(res)).toBe(true); + + const indices = await client.indices.get({ + index: ['existing_index_with_docs'], + }); + + expect(indices.existing_index_with_docs.mappings?.properties).toEqual( + expect.objectContaining({ + created_at: { + type: 'date', + }, + }) + ); + + expect(indices.existing_index_with_docs.mappings?._meta).toEqual({ + migrationMappingPropertyHashes: { + references: 'updateda56cc02bdc9c93361bupdated', + newReferences: 'fooBarHashMd509387420934879300d9', + }, + }); + }); + }); + + describe('updateAliases', () => { + describe('remove', () => { + it('resolves left index_not_found_exception when the index does not exist', async () => { + const task = updateAliases({ + client, + aliasActions: [ + { + remove: { + alias: 'no_such_alias', + index: 'no_such_index', + must_exist: false, + }, + }, + ], + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "index": "no_such_index", + "type": "index_not_found_exception", + }, + } + `); + }); + describe('with must_exist=false', () => { + it('resolves left alias_not_found_exception when alias does not exist', async () => { + const task = updateAliases({ + client, + aliasActions: [ + { + remove: { + alias: 'no_such_alias', + index: 'existing_index_with_docs', + must_exist: false, + }, + }, + ], + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "alias_not_found_exception", + }, + } + `); + }); + }); + describe('with must_exist=true', () => { + it('resolves left alias_not_found_exception when alias does not exist on specified index', async () => { + const task = updateAliases({ + client, + aliasActions: [ + { + remove: { + alias: 'existing_index_2_alias', + index: 'existing_index_with_docs', + must_exist: true, + }, + }, + ], + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "alias_not_found_exception", + }, + } + `); + }); + it('resolves left alias_not_found_exception when alias does not exist', async () => { + const task = updateAliases({ + client, + aliasActions: [ + { + remove: { + alias: 'no_such_alias', + index: 'existing_index_with_docs', + must_exist: true, + }, + }, + ], + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "alias_not_found_exception", + }, + } + `); + }); + }); + }); + describe('remove_index', () => { + it('left index_not_found_exception if index does not exist', async () => { + const task = updateAliases({ + client, + aliasActions: [ + { + remove_index: { + index: 'no_such_index', + }, + }, + ], + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "index": "no_such_index", + "type": "index_not_found_exception", + }, + } + `); + }); + it('left remove_index_not_a_concrete_index when remove_index targets an alias', async () => { + const task = updateAliases({ + client, + aliasActions: [ + { + remove_index: { + index: 'existing_index_2_alias', + }, + }, + ], + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "remove_index_not_a_concrete_index", + }, + } + `); + }); + }); + }); + + describe('createIndex', () => { + afterEach(async () => { + // Restore the default setting of 1000 shards per node + await client.cluster.putSettings({ persistent: { cluster: { max_shards_per_node: null } } }); + }); + afterAll(async () => { + await client.indices.delete({ index: 'red_then_yellow_index' }).catch(); + await client.indices.delete({ index: 'yellow_then_green_index' }).catch(); + await client.indices.delete({ index: 'create_new_index' }).catch(); + }); + it('resolves right after waiting for an index status to become green when cluster state is not propagated within the timeout', async () => { + // By specifying a very short timeout Elasticsearch will respond before the shard is allocated + const createIndexPromise = createIndex({ + client, + indexName: 'create_new_index', + mappings: undefined as any, + timeout: '1nanos', + esCapabilities, + })(); + await expect(createIndexPromise).resolves.toEqual({ + _tag: 'Right', + right: 'create_index_succeeded', + }); + const { create_new_index: createNewIndex } = await client.indices.getSettings({ + index: 'create_new_index', + }); + // @ts-expect-error https://github.com/elastic/elasticsearch/issues/89381 + expect(createNewIndex.settings?.index?.mapping.total_fields.limit).toBe('1500'); + }); + it('resolves left if an existing index status does not become green', async () => { + expect.assertions(2); + // Create a red index + await client.indices + .create( + { + index: 'red_then_yellow_index', + timeout: '5s', + body: { + mappings: { properties: {} }, + settings: { + // Allocate 1 replica so that this index stays yellow + number_of_replicas: '1', + // Disable all shard allocation so that the index status starts as red + index: { routing: { allocation: { enable: 'none' } } }, + }, + }, + }, + { maxRetries: 0 /** handle retry ourselves for now */ } + ) + .catch((e) => { + /** ignore */ + }); + + // Call createIndex even though the index already exists + const createIndexPromise = createIndex({ + client, + indexName: 'red_then_yellow_index', + mappings: undefined as any, + esCapabilities, + })(); + let indexYellow = false; + + setTimeout(() => { + client.indices.putSettings({ + index: 'red_then_yellow_index', + body: { + // Renable allocation so that the status becomes yellow + routing: { allocation: { enable: 'all' } }, + }, + }); + indexYellow = true; + }, 10); + + await createIndexPromise.then((err) => { + // Assert that the promise didn't resolve before the index became yellow + expect(indexYellow).toBe(true); + expect(err).toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "message": "[index_not_green_timeout] Timeout waiting for the status of the [red_then_yellow_index] index to become 'green'", + "type": "index_not_green_timeout", + }, + } + `); + }); + }); + it('resolves right after waiting for an existing index status to become green', async () => { + expect.assertions(2); + // Create a yellow index + await client.indices + .create({ + index: 'yellow_then_green_index', + timeout: '5s', + body: { + mappings: { properties: {} }, + settings: { + // Allocate 1 replica so that this index stays yellow + number_of_replicas: '1', + }, + }, + }) + .catch((e) => { + /** ignore */ + }); + + // Call createIndex even though the index already exists + const createIndexPromise = createIndex({ + client, + indexName: 'yellow_then_green_index', + mappings: undefined as any, + esCapabilities, + })(); + let indexGreen = false; + + setTimeout(() => { + client.indices.putSettings({ + index: 'yellow_then_green_index', + body: { + // Set 0 replican so that this index becomes green + number_of_replicas: '0', + }, + }); + indexGreen = true; + }, 10); + + await createIndexPromise.then((res) => { + // Assert that the promise didn't resolve before the index became green + expect(indexGreen).toBe(true); + expect(res).toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "index_already_exists", + } + `); + }); + }); + it('resolves left cluster_shard_limit_exceeded when the action would exceed the maximum normal open shards', async () => { + // Set the max shards per node really low so that any new index that's created would exceed the maximum open shards for this cluster + await client.cluster.putSettings({ persistent: { cluster: { max_shards_per_node: 1 } } }); + const createIndexPromise = createIndex({ + client, + indexName: 'create_index_1', + mappings: undefined as any, + esCapabilities, + })(); + await expect(createIndexPromise).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "cluster_shard_limit_exceeded", + }, + } + `); + }); + it('rejects when there is an unexpected error creating the index', async () => { + // Creating an index with the same name as an existing alias to induce + // failure + await expect( + createIndex({ + client, + indexName: 'existing_index_2_alias', + mappings: undefined as any, + esCapabilities, + })() + ).rejects.toThrow('invalid_index_name_exception'); + }); + }); + + describe('bulkOverwriteTransformedDocuments', () => { + it('resolves right when documents do not yet exist in the index', async () => { + const newDocs = [ + { _source: { title: 'doc 5' } }, + { _source: { title: 'doc 6' } }, + { _source: { title: 'doc 7' } }, + ] as unknown as SavedObjectsRawDoc[]; + const task = bulkOverwriteTransformedDocuments({ + client, + index: 'existing_index_with_docs', + operations: newDocs.map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + }); + + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "bulk_index_succeeded", + } + `); + }); + it('resolves right even if there were some version_conflict_engine_exception', async () => { + const response = await client.search({ index: 'existing_index_with_docs', size: 1000 }); + const existingDocs = response.hits?.hits as SavedObjectsRawDoc[]; + + const task = bulkOverwriteTransformedDocuments({ + client, + index: 'existing_index_with_docs', + operations: [ + ...existingDocs, + { _source: { title: 'doc 8' } } as unknown as SavedObjectsRawDoc, + ].map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Right", + "right": "bulk_index_succeeded", + } + `); + }); + it('resolves left index_not_found_exception if the index does not exist and useAliasToPreventAutoCreate=true', async () => { + const newDocs = [ + { _source: { title: 'doc 5' } }, + { _source: { title: 'doc 6' } }, + { _source: { title: 'doc 7' } }, + ] as unknown as SavedObjectsRawDoc[]; + await expect( + bulkOverwriteTransformedDocuments({ + client, + index: 'existing_index_with_docs_alias_that_does_not_exist', + useAliasToPreventAutoCreate: true, + operations: newDocs.map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + })() + ).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "index": "existing_index_with_docs_alias_that_does_not_exist", + "type": "index_not_found_exception", + }, + } + `); + }); + it('resolves left target_index_had_write_block if there are write_block errors', async () => { + const newDocs = [ + { _source: { title: 'doc 5' } }, + { _source: { title: 'doc 6' } }, + { _source: { title: 'doc 7' } }, + ] as unknown as SavedObjectsRawDoc[]; + await expect( + bulkOverwriteTransformedDocuments({ + client, + index: 'existing_index_with_write_block', + operations: newDocs.map((doc) => createBulkIndexOperationTuple(doc)), + refresh: 'wait_for', + })() + ).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "target_index_had_write_block", + }, + } + `); + }); + + it('resolves left request_entity_too_large_exception when the payload is too large', async () => { + const newDocs = new Array(10000).fill({ + _source: { + title: + 'how do I create a document thats large enoug to exceed the limits without typing long sentences', + }, + }) as SavedObjectsRawDoc[]; + const task = bulkOverwriteTransformedDocuments({ + client, + index: 'existing_index_with_docs', + operations: newDocs.map((doc) => createBulkIndexOperationTuple(doc)), + }); + await expect(task()).resolves.toMatchInlineSnapshot(` + Object { + "_tag": "Left", + "left": Object { + "type": "request_entity_too_large_exception", + }, + } + `); + }); }); }); diff --git a/src/dev/so_migration/compare_snapshots.ts b/src/dev/so_migration/compare_snapshots.ts new file mode 100644 index 00000000000000..3f5563c1891387 --- /dev/null +++ b/src/dev/so_migration/compare_snapshots.ts @@ -0,0 +1,180 @@ +/* + * 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 { ToolingLog } from '@kbn/tooling-log'; +import { readFile } from 'fs/promises'; +import { existsSync, mkdirSync, writeFileSync } from 'fs'; +import * as os from 'os'; +import { execSync } from 'child_process'; +import { basename, dirname, resolve } from 'path'; +import { MigrationInfoRecord, MigrationSnapshot } from './types'; +import { downloadFile } from './util/download_file'; + +const SO_MIGRATIONS_BUCKET_PREFIX = 'https://storage.googleapis.com/kibana-so-types-snapshots'; + +interface CompareSnapshotsParameters { + from: string; + to: string; + log: ToolingLog; + outputPath?: string; +} + +async function compareSnapshots({ + outputPath, + log, + from, + to, +}: CompareSnapshotsParameters): Promise { + validateInput({ + from, + to, + }); + + const fromSnapshotPath = isFile(from) ? from : await downloadSnapshot(from, log); + const toSnapshotPath = isFile(to) ? to : await downloadSnapshot(to, log); + + const fromSnapshot = await loadJson(fromSnapshotPath); + const toSnapshot = await loadJson(toSnapshotPath); + + const result = compareSnapshotFiles(fromSnapshot, toSnapshot); + + log.info( + `Snapshots compared: ${from} <=> ${to}. ` + + `${result.hasChanges ? 'No changes' : 'Changed: ' + result.changed.join(', ')}` + ); + + if (outputPath) { + writeSnapshot(outputPath, result); + log.info(`Output written to: ${outputPath}`); + } else { + log.info( + `Emitting result to STDOUT... (Enable '--silent' or '--quiet' to disable non-parseable output)` + ); + // eslint-disable-next-line no-console + console.log(JSON.stringify(result, null, 2)); + } + + return result; +} + +function validateInput({ from, to }: { from: string; to: string }) { + if (!from || !to) { + throw new Error('"--from" and "--to" must be specified'); + } + + if (from === to) { + throw new Error('"from" and "to" must be different'); + } +} + +function writeSnapshot(outputPath: string, result: any) { + const json = JSON.stringify(result, null, 2); + mkdirSync(dirname(outputPath), { recursive: true }); + writeFileSync(outputPath, json); +} + +function isFile(str: string) { + try { + return existsSync(str); + } catch (err) { + return false; + } +} + +async function downloadToTemp(googleCloudUrl: string, log: ToolingLog): Promise { + const fileName = basename(googleCloudUrl); + const filePath = resolve(os.tmpdir(), fileName); + + if (existsSync(filePath)) { + log.info('Snapshot already exists at: ' + filePath); + return filePath; + } else { + try { + log.info('Downloading snapshot from: ' + googleCloudUrl); + await downloadFile(googleCloudUrl, filePath); + log.info('File downloaded: ' + filePath); + return filePath; + } catch (err) { + log.error("Couldn't download snapshot from: " + googleCloudUrl); + throw err; + } + } +} + +function downloadSnapshot(gitRev: string, log: ToolingLog): Promise { + const fullCommitHash = expandGitRev(gitRev); + const googleCloudUrl = `${SO_MIGRATIONS_BUCKET_PREFIX}/${fullCommitHash}.json`; + + return downloadToTemp(googleCloudUrl, log); +} + +function expandGitRev(gitRev: string) { + if (gitRev.match(/^[0-9a-f]{40}$/)) { + return gitRev; + } else { + try { + return execSync(`git rev-parse ${gitRev}`, { stdio: ['pipe', 'pipe', null] }) + .toString() + .trim(); + } catch (err) { + throw new Error(`Couldn't expand git rev: ${gitRev} - ${err.message}`); + } + } +} + +/** + * Collects all plugin names that have different hashes in the two snapshots. + * @param fromSnapshot + * @param toSnapshot + */ +function compareSnapshotFiles(fromSnapshot: MigrationSnapshot, toSnapshot: MigrationSnapshot) { + const pluginNames = Object.keys(fromSnapshot.typeDefinitions); + const pluginNamesWithChangedHash = pluginNames.filter((pluginName) => { + const fromHash = fromSnapshot.typeDefinitions[pluginName].hash; + const toHash = toSnapshot.typeDefinitions[pluginName].hash; + return fromHash !== toHash; + }); + + const restOfPluginNames = pluginNames.filter((e) => !pluginNamesWithChangedHash.includes(e)); + + const changes = pluginNamesWithChangedHash.reduce((changesObj, pluginName) => { + const fromMigrationInfo = fromSnapshot.typeDefinitions[pluginName]; + const toMigrationInfo = toSnapshot.typeDefinitions[pluginName]; + changesObj[pluginName] = { + from: fromMigrationInfo, + to: toMigrationInfo, + }; + return changesObj; + }, {} as Record); + + return { + hasChanges: pluginNamesWithChangedHash.length > 0, + from: fromSnapshot.meta.kibanaCommitHash, + to: toSnapshot.meta.kibanaCommitHash, + changed: pluginNamesWithChangedHash, + unchanged: restOfPluginNames, + changes, + }; +} + +async function loadJson(filePath: string) { + try { + const fileContent = await readFile(filePath, { encoding: 'utf-8' }); + return JSON.parse(fileContent); + } catch (err) { + if (err.code === 'ENOENT') { + throw new Error(`Snapshot file not found: ${filePath}`); + } else if (err.message.includes('Unexpected token')) { + throw new Error(`Snapshot file is not a valid JSON: ${filePath}`); + } else { + throw err; + } + } +} + +export { compareSnapshots }; diff --git a/src/dev/so_migration/snapshot_plugin_types.ts b/src/dev/so_migration/snapshot_plugin_types.ts index 26cca555e28c51..288f4704d19f8d 100644 --- a/src/dev/so_migration/snapshot_plugin_types.ts +++ b/src/dev/so_migration/snapshot_plugin_types.ts @@ -10,30 +10,15 @@ import * as fs from 'fs'; import * as path from 'path'; import * as cp from 'child_process'; -import { - extractMigrationInfo, - getMigrationHash, - SavedObjectTypeMigrationInfo, - // TODO: how to resolve this? Where to place this script? - // eslint-disable-next-line @kbn/imports/no_boundary_crossing -} from '@kbn/core-test-helpers-so-type-serializer'; -import { - createTestServers, - createRootWithCorePlugins, - // TODO: how to resolve this? Where to place this script? - // eslint-disable-next-line @kbn/imports/no_boundary_crossing -} from '@kbn/core-test-helpers-kbn-server'; +// eslint-disable-next-line @kbn/imports/no_boundary_crossing +import { extractMigrationInfo, getMigrationHash } from '@kbn/core-test-helpers-so-type-serializer'; +// eslint-disable-next-line @kbn/imports/no_boundary_crossing +import { createRootWithCorePlugins, createTestServers } from '@kbn/core-test-helpers-kbn-server'; import { REPO_ROOT } from '@kbn/repo-info'; import { ToolingLog } from '@kbn/tooling-log'; import { mkdirp } from '../build/lib'; - -type MigrationInfoRecord = Pick< - SavedObjectTypeMigrationInfo, - 'name' | 'migrationVersions' | 'schemaVersions' | 'modelVersions' | 'mappings' -> & { - hash: string; -}; +import type { MigrationSnapshot, MigrationInfoRecord, MigrationSnapshotMeta } from './types'; type ServerHandles = Awaited> | undefined; @@ -68,7 +53,12 @@ async function takeSnapshot({ log, outputPath }: { log: ToolingLog; outputPath: return map; }, {} as Record); - await writeSnapshotFile(snapshotOutputPath, migrationInfoMap); + const payload: MigrationSnapshot = { + meta: collectSOSnapshotMeta(), + typeDefinitions: migrationInfoMap, + }; + + await writeSnapshotFile(snapshotOutputPath, payload); log.info('Snapshot taken!'); return migrationInfoMap; @@ -91,30 +81,26 @@ async function startServers() { return { esServer, kibanaRoot, coreStart }; } -async function writeSnapshotFile( - snapshotOutputPath: string, - typeDefinitions: Record -) { +async function writeSnapshotFile(snapshotOutputPath: string, payload: MigrationSnapshot) { + await mkdirp(path.dirname(snapshotOutputPath)); + fs.writeFileSync(snapshotOutputPath, JSON.stringify(payload, null, 2)); +} + +function collectSOSnapshotMeta(): MigrationSnapshotMeta { const timestamp = Date.now(); const date = new Date().toISOString(); - const buildUrl = process.env.BUILDKITE_BUILD_URL; + const buildUrl = process.env.BUILDKITE_BUILD_URL || null; const prId = process.env.BUILDKITE_MESSAGE?.match(/\(#(\d+)\)/)?.[1]; const pullRequestUrl = prId ? `https://github.com/elastic/kibana/pulls/${prId}` : null; const kibanaCommitHash = process.env.BUILDKITE_COMMIT || getLocalHash(); - const payload = { - meta: { - timestamp, - date, - kibanaCommitHash, - buildUrl, - pullRequestUrl, - }, - typeDefinitions, + return { + timestamp, + date, + kibanaCommitHash, + buildUrl, + pullRequestUrl, }; - - await mkdirp(path.dirname(snapshotOutputPath)); - fs.writeFileSync(snapshotOutputPath, JSON.stringify(payload, null, 2)); } async function shutdown(log: ToolingLog, serverHandles: ServerHandles) { diff --git a/src/dev/so_migration/so_migration_compare_cli.ts b/src/dev/so_migration/so_migration_compare_cli.ts new file mode 100644 index 00000000000000..33eaee9f4cbf08 --- /dev/null +++ b/src/dev/so_migration/so_migration_compare_cli.ts @@ -0,0 +1,58 @@ +/* + * 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 { run } from '@kbn/dev-cli-runner'; + +import { compareSnapshots } from './compare_snapshots'; + +const scriptName = process.argv[1].replace(/^.*scripts\//, 'scripts/'); + +run( + async ({ log, flagsReader, procRunner }) => { + const outputPath = flagsReader.string('outputPath'); + + const from = flagsReader.requiredString('from'); + const to = flagsReader.requiredString('to'); + + const result = await compareSnapshots({ from, to, outputPath, log }); + + return { + outputPath, + result, + log, + }; + }, + { + usage: [ + process.argv0, + scriptName, + 'compare', + '--from ', + '--to ', + '[--outputPath ]', + ].join(' '), + description: `Compares two Saved Object snapshot files based on hashes, filenames or urls.`, + flags: { + string: ['outputPath', 'from', 'to'], + help: ` + --from The source snapshot to compare from. Can be a revision, filename or url. + --to The target snapshot to compare to. Can be a revision, filename or url. + --outputPath The path to write the comparison report to. If omitted, raw JSON will be output to stdout. + `, + }, + } +) + .then((success) => { + // Kibana won't stop because some async processes are stuck polling, we need to shut down the process. + process.exit(0); + }) + .catch((err) => { + // eslint-disable-next-line no-console + console.error(err); + process.exit(1); + }); diff --git a/src/dev/so_migration/so_migration_cli.ts b/src/dev/so_migration/so_migration_snapshot_cli.ts similarity index 89% rename from src/dev/so_migration/so_migration_cli.ts rename to src/dev/so_migration/so_migration_snapshot_cli.ts index 3701efac703536..d919488fc744a4 100644 --- a/src/dev/so_migration/so_migration_cli.ts +++ b/src/dev/so_migration/so_migration_snapshot_cli.ts @@ -15,7 +15,7 @@ const DEFAULT_OUTPUT_PATH = 'target/plugin_so_types_snapshot.json'; run( async ({ log, flagsReader, procRunner }) => { - const outputPath = flagsReader.getPositionals()[0] || DEFAULT_OUTPUT_PATH; + const outputPath = flagsReader.string('outputPath') || DEFAULT_OUTPUT_PATH; const result = await takeSnapshot({ outputPath, log }); @@ -26,7 +26,7 @@ run( }; }, { - usage: [process.argv0, scriptName, '[outputPath]'].join(' '), + usage: [process.argv0, scriptName, 'snapshot', '[--outputPath ]'].join(' '), description: `Takes a snapshot of all Kibana plugin Saved Object migrations' information, in a JSON format.`, flags: { string: ['outputPath'], diff --git a/src/dev/so_migration/types.d.ts b/src/dev/so_migration/types.d.ts new file mode 100644 index 00000000000000..695fec1f487d71 --- /dev/null +++ b/src/dev/so_migration/types.d.ts @@ -0,0 +1,29 @@ +/* + * 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 type { SavedObjectTypeMigrationInfo } from '@kbn/core-test-helpers-so-type-serializer'; + +export type MigrationInfoRecord = Pick< + SavedObjectTypeMigrationInfo, + 'name' | 'migrationVersions' | 'schemaVersions' | 'modelVersions' | 'mappings' +> & { + hash: string; +}; + +export interface MigrationSnapshotMeta { + date: string; + kibanaCommitHash: string | null; + buildUrl: string | null; + pullRequestUrl: string | null; + timestamp: number; +} + +export interface MigrationSnapshot { + meta: MigrationSnapshotMeta; + typeDefinitions: Record; +} diff --git a/src/dev/so_migration/util/download_file.ts b/src/dev/so_migration/util/download_file.ts new file mode 100644 index 00000000000000..080d6fe0e6ff89 --- /dev/null +++ b/src/dev/so_migration/util/download_file.ts @@ -0,0 +1,34 @@ +/* + * 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 { createWriteStream, unlinkSync } from 'fs'; +import https from 'https'; + +export function downloadFile(url: string, outputPath: string) { + const file = createWriteStream(outputPath); + + return new Promise((res, rej) => { + https + .get(url, (response) => { + if (response.statusCode !== 200) { + rej(response.statusMessage); + } else { + response.pipe(file); + + file.on('finish', () => { + file.close(); + res(undefined); + }); + } + }) + .on('error', (err) => { + unlinkSync(outputPath); + rej(err); + }); + }); +} diff --git a/src/plugins/data/public/search/search_service.ts b/src/plugins/data/public/search/search_service.ts index d70d553ae05c12..f3360964686061 100644 --- a/src/plugins/data/public/search/search_service.ts +++ b/src/plugins/data/public/search/search_service.ts @@ -257,18 +257,18 @@ export class SearchService implements Plugin { if (!options.disableWarningToasts) { const { rawResponse } = response; + const requestName = options.inspector?.title + ? options.inspector.title + : i18n.translate('data.searchService.anonymousRequestTitle', { + defaultMessage: 'Request', + }); const requestAdapter = options.inspector?.adapter ? options.inspector?.adapter : new RequestAdapter(); if (!options.inspector?.adapter) { - const requestResponder = requestAdapter.start( - i18n.translate('data.searchService.anonymousRequestTitle', { - defaultMessage: 'Request', - }), - { - id: request.id, - } - ); + const requestResponder = requestAdapter.start(requestName, { + id: request.id, + }); requestResponder.json(request.body); requestResponder.ok({ json: response }); } @@ -277,6 +277,7 @@ export class SearchService implements Plugin { request: request.body as estypes.SearchRequest, requestAdapter, requestId: request.id, + requestName, response: rawResponse, services: warningsServices, }); @@ -325,6 +326,7 @@ export class SearchService implements Plugin { request: request.json as estypes.SearchRequest, requestAdapter: adapter, requestId: request.id, + requestName: request.name, response: rawResponse, services: warningsServices, }); diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx b/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx index 2ab485fdb1de1f..71ff8ce38636ce 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern.tsx @@ -6,7 +6,7 @@ * Side Public License, v 1. */ -import React, { useEffect, useState, useCallback } from 'react'; +import React, { useEffect, useState, useCallback, useMemo } from 'react'; import { withRouter, RouteComponentProps, useLocation } from 'react-router-dom'; import { EuiFlexGroup, @@ -17,6 +17,7 @@ import { EuiCallOut, EuiCode, EuiText, + EuiLink, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -28,11 +29,13 @@ import { SavedObjectManagementTypeInfo, } from '@kbn/saved-objects-management-plugin/public'; import { pickBy } from 'lodash'; +import { setStateToKbnUrl } from '@kbn/kibana-utils-plugin/public'; import { IndexPatternManagmentContext } from '../../types'; import { Tabs } from './tabs'; import { IndexHeader } from './index_header'; import { getTags } from '../utils'; import { removeDataView, RemoveDataViewProps } from './remove_data_view'; +import { APP_STATE_STORAGE_KEY } from './edit_index_pattern_state_container'; const codeStyle = { marginLeft: '8px', @@ -67,8 +70,15 @@ const getCompositeRuntimeFields = (dataView: DataView) => export const EditIndexPattern = withRouter( ({ indexPattern, history, location }: EditIndexPatternProps) => { - const { uiSettings, overlays, chrome, dataViews, IndexPatternEditor, savedObjectsManagement } = - useKibana().services; + const { + uiSettings, + overlays, + chrome, + dataViews, + IndexPatternEditor, + savedObjectsManagement, + application, + } = useKibana().services; const [fields, setFields] = useState(indexPattern.getNonScriptedFields()); const [compositeRuntimeFields, setCompositeRuntimeFields] = useState< Record @@ -83,6 +93,31 @@ export const EditIndexPattern = withRouter( const [showEditDialog, setShowEditDialog] = useState(false); const [relationships, setRelationships] = useState([]); const [allowedTypes, setAllowedTypes] = useState([]); + const conflictFieldsUrl = useMemo(() => { + return setStateToKbnUrl( + APP_STATE_STORAGE_KEY, + { + fieldTypes: ['conflict'], + tab: 'indexedFields', + }, + { useHash: uiSettings.get('state:storeInSessionStorage') }, + application.getUrlForApp('management', { + path: `/kibana/dataViews/dataView/${encodeURIComponent(indexPattern.id!)}`, + }) + ); + }, [application, indexPattern.id, uiSettings]); + + useEffect(() => { + // dispatch synthetic hash change event to update hash history objects + // this is necessary because hash updates triggered by using popState won't trigger this event naturally. + const unlistenParentHistory = history.listen(() => { + window.dispatchEvent(new HashChangeEvent('hashchange')); + }); + + return () => { + unlistenParentHistory(); + }; + }, [history]); useEffect(() => { savedObjectsManagement.getAllowedTypes().then((resp) => { @@ -259,8 +294,24 @@ export const EditIndexPattern = withRouter( {conflictedFields.length > 0 && ( <> - +

{mappingConflictLabel}

+ + {i18n.translate( + 'indexPatternManagement.editIndexPattern.viewMappingConflictButton', + { + defaultMessage: 'View conflicts', + } + )} +
)} diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern_state_container.ts b/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern_state_container.ts index 6252ea3ae6ad83..e3979345f7713d 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern_state_container.ts +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/edit_index_pattern_state_container.ts @@ -15,8 +15,14 @@ import { interface IEditIndexPatternState { tab: string; + fieldTypes?: string[]; + schemaFieldTypes?: string[]; + fieldFilter?: string; } +// query param to store app state at +export const APP_STATE_STORAGE_KEY = '_a'; + /** * Create state container with sync config for tab navigation specific for edit_index_pattern page */ @@ -28,8 +34,6 @@ export function createEditIndexPatternPageStateContainer({ useHashedUrl: boolean; }) { const history = createHashHistory(); - // query param to store app state at - const stateStorageKey = '_a'; // default app state, when there is no initial state in the url const defaultState = { tab: defaultTab, @@ -39,7 +43,7 @@ export function createEditIndexPatternPageStateContainer({ history, }); // extract starting app state from URL and use it as starting app state in state container - const initialStateFromUrl = kbnUrlStateStorage.get(stateStorageKey); + const initialStateFromUrl = kbnUrlStateStorage.get(APP_STATE_STORAGE_KEY); const stateContainer = createStateContainer( { ...defaultState, @@ -47,14 +51,30 @@ export function createEditIndexPatternPageStateContainer({ }, { setTab: (state: IEditIndexPatternState) => (tab: string) => ({ ...state, tab }), + setFieldFilter: (state: IEditIndexPatternState) => (fieldFilter: string | undefined) => ({ + ...state, + fieldFilter, + }), + setFieldTypes: (state: IEditIndexPatternState) => (fieldTypes: string[] | undefined) => ({ + ...state, + fieldTypes: fieldTypes?.length ? fieldTypes : undefined, + }), + setSchemaFieldTypes: + (state: IEditIndexPatternState) => (schemaFieldTypes: string[] | undefined) => ({ + ...state, + schemaFieldTypes: schemaFieldTypes?.length ? schemaFieldTypes : undefined, + }), }, { tab: (state: IEditIndexPatternState) => () => state.tab, + fieldFilter: (state: IEditIndexPatternState) => () => state.fieldFilter, + fieldTypes: (state: IEditIndexPatternState) => () => state.fieldTypes, + schemaFieldTypes: (state: IEditIndexPatternState) => () => state.schemaFieldTypes, } ); const { start, stop } = syncState({ - storageKey: stateStorageKey, + storageKey: APP_STATE_STORAGE_KEY, stateContainer: { ...stateContainer, // state syncing utility requires state containers to handle "null" @@ -64,12 +84,18 @@ export function createEditIndexPatternPageStateContainer({ }); // makes sure initial url is the same as initial state (this is not really required) - kbnUrlStateStorage.set(stateStorageKey, stateContainer.getState(), { replace: true }); + kbnUrlStateStorage.set(APP_STATE_STORAGE_KEY, stateContainer.getState(), { replace: true }); return { + stateContainer, startSyncingState: start, stopSyncingState: stop, setCurrentTab: (newTab: string) => stateContainer.transitions.setTab(newTab), - getCurrentTab: () => stateContainer.selectors.tab(), + setCurrentFieldFilter: (newFieldFilter: string | undefined) => + stateContainer.transitions.setFieldFilter(newFieldFilter), + setCurrentFieldTypes: (newFieldTypes: string[] | undefined) => + stateContainer.transitions.setFieldTypes(newFieldTypes), + setCurrentSchemaFieldTypes: (newSchemaFieldTypes: string[] | undefined) => + stateContainer.transitions.setSchemaFieldTypes(newSchemaFieldTypes), }; } diff --git a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/__snapshots__/table.test.tsx.snap b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/__snapshots__/table.test.tsx.snap index aac14c81fe6dc9..e3af6faa7985ac 100644 --- a/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/__snapshots__/table.test.tsx.snap +++ b/src/plugins/data_view_management/public/components/edit_index_pattern/indexed_fields_table/components/table/__snapshots__/table.test.tsx.snap @@ -109,6 +109,7 @@ exports[`Table should render conflicting type 1`] = ` text, long + + {' '} = ({ indexPattern, saveIndexPattern, fields, @@ -147,7 +159,7 @@ export function Tabs({ relationships, allowedTypes, compositeRuntimeFields, -}: TabsProps) { +}) => { const { uiSettings, docLinks, @@ -161,11 +173,17 @@ export function Tabs({ } = useKibana().services; const [fieldFilter, setFieldFilter] = useState(''); const [syncingStateFunc, setSyncingStateFunc] = useState<{ - getCurrentTab: () => string; setCurrentTab?: (newTab: string) => { tab: string }; - }>({ - getCurrentTab: () => TAB_INDEXED_FIELDS, - }); + setCurrentFieldFilter?: (newFieldFilter: string | undefined) => { + fieldFilter: string | undefined; + }; + setCurrentFieldTypes?: (newFieldTypes: string[] | undefined) => { + fieldTypes: string[] | undefined; + }; + setCurrentSchemaFieldTypes?: (newSchemaFieldTypes: string[] | undefined) => { + schemaFieldTypes: string[] | undefined; + }; + }>({}); const [scriptedFieldLanguageFilter, setScriptedFieldLanguageFilter] = useState([]); const [isScriptedFieldFilterOpen, setIsScriptedFieldFilterOpen] = useState(false); const [scriptedFieldLanguages, setScriptedFieldLanguages] = useState([]); @@ -174,19 +192,53 @@ export function Tabs({ const [indexedFieldTypes, setIndexedFieldTypes] = useState([]); const [schemaFieldTypeFilter, setSchemaFieldTypeFilter] = useState([]); const [isSchemaFilterOpen, setIsSchemaFilterOpen] = useState(false); - const [schemaItems, setSchemaItems] = useState([ - { - value: 'runtime', - name: schemaOptionRuntime, - }, - { - value: 'indexed', - name: schemaOptionIndexed, - }, - ]); const closeEditorHandler = useRef<() => void | undefined>(); const { DeleteRuntimeFieldProvider } = dataViewFieldEditor; + const filteredIndexedFieldTypeFilter = useMemo(() => { + return uniq( + indexedFieldTypeFilter.filter((fieldType) => + indexedFieldTypes.some((item) => item.value === fieldType) + ) + ); + }, [indexedFieldTypeFilter, indexedFieldTypes]); + + const filteredSchemaFieldTypeFilter = useMemo(() => { + return uniq( + schemaFieldTypeFilter.filter((schemaFieldType) => + SCHEMA_ITEMS.some((item) => item.value === schemaFieldType) + ) + ); + }, [schemaFieldTypeFilter]); + + const updateTab = useCallback( + (tab: Pick) => { + syncingStateFunc.setCurrentTab?.(tab.id); + }, + [syncingStateFunc] + ); + + const updateFieldTypeFilter = useCallback( + (newIndexedFieldTypeFilter: string[]) => { + syncingStateFunc?.setCurrentFieldTypes?.(newIndexedFieldTypeFilter); + }, + [syncingStateFunc] + ); + + const updateSchemaFieldTypeFilter = useCallback( + (newSchemaFieldTypeFilter: string[]) => { + syncingStateFunc?.setCurrentSchemaFieldTypes?.(newSchemaFieldTypeFilter); + }, + [syncingStateFunc] + ); + + const updateFieldFilter = useCallback( + (newFieldFilter: string) => { + syncingStateFunc?.setCurrentFieldFilter?.(newFieldFilter || undefined); + }, + [syncingStateFunc] + ); + const updateFilterItem = ( items: FilterItems[], index: number, @@ -279,7 +331,7 @@ export function Tabs({ fullWidth placeholder={filterPlaceholder} value={fieldFilter} - onChange={(e) => setFieldFilter(e.target.value)} + onChange={(e) => updateFieldFilter(e.target.value)} data-test-subj="indexPatternFieldFilter" aria-label={searchAriaLabel} /> @@ -299,10 +351,8 @@ export function Tabs({ onClick={() => setIsIndexedFilterOpen(!isIndexedFilterOpen)} isSelected={isIndexedFilterOpen} numFilters={indexedFieldTypes.length} - hasActiveFilters={!!indexedFieldTypes.find((item) => item.checked === 'on')} - numActiveFilters={ - indexedFieldTypes.filter((item) => item.checked === 'on').length - } + hasActiveFilters={filteredIndexedFieldTypeFilter.length > 0} + numActiveFilters={filteredIndexedFieldTypeFilter.length} > {filterLabel} @@ -310,25 +360,27 @@ export function Tabs({ isOpen={isIndexedFilterOpen} closePopover={() => setIsIndexedFilterOpen(false)} > - {indexedFieldTypes.map((item, index) => ( - { - setIndexedFieldTypeFilter( - item.checked - ? indexedFieldTypeFilter.filter((f) => f !== item.value) - : [...indexedFieldTypeFilter, item.value] - ); - updateFilterItem(indexedFieldTypes, index, setIndexedFieldTypes); - }} - data-test-subj={`indexedFieldTypeFilterDropdown-option-${item.value}${ - item.checked ? '-checked' : '' - }`} - > - {item.name} - - ))} + {indexedFieldTypes.map((item, index) => { + const isSelected = filteredIndexedFieldTypeFilter.includes(item.value); + return ( + { + updateFieldTypeFilter( + isSelected + ? filteredIndexedFieldTypeFilter.filter((f) => f !== item.value) + : [...filteredIndexedFieldTypeFilter, item.value] + ); + }} + data-test-subj={`indexedFieldTypeFilterDropdown-option-${item.value}${ + isSelected ? '-checked' : '' + }`} + > + {item.name} + + ); + })} setIsSchemaFilterOpen(!isSchemaFilterOpen)} isSelected={isSchemaFilterOpen} - numFilters={schemaItems.length} - hasActiveFilters={!!schemaItems.find((item) => item.checked === 'on')} - numActiveFilters={ - schemaItems.filter((item) => item.checked === 'on').length - } + numFilters={SCHEMA_ITEMS.length} + hasActiveFilters={filteredSchemaFieldTypeFilter.length > 0} + numActiveFilters={filteredSchemaFieldTypeFilter.length} > {schemaFilterLabel} @@ -352,25 +402,27 @@ export function Tabs({ isOpen={isSchemaFilterOpen} closePopover={() => setIsSchemaFilterOpen(false)} > - {schemaItems.map((item, index) => ( - { - setSchemaFieldTypeFilter( - item.checked - ? schemaFieldTypeFilter.filter((f) => f !== item.value) - : [...schemaFieldTypeFilter, item.value] - ); - updateFilterItem(schemaItems, index, setSchemaItems); - }} - data-test-subj={`schemaFieldTypeFilterDropdown-option-${item.value}${ - item.checked ? '-checked' : '' - }`} - > - {item.name} - - ))} + {SCHEMA_ITEMS.map((item) => { + const isSelected = filteredSchemaFieldTypeFilter.includes(item.value); + return ( + { + updateSchemaFieldTypeFilter( + isSelected + ? filteredSchemaFieldTypeFilter.filter((f) => f !== item.value) + : [...filteredSchemaFieldTypeFilter, item.value] + ); + }} + data-test-subj={`schemaFieldTypeFilterDropdown-option-${item.value}${ + isSelected ? '-checked' : '' + }`} + > + {item.name} + + ); + })} @@ -438,17 +490,19 @@ export function Tabs({ }, [ fieldFilter, - indexedFieldTypeFilter, + filteredSchemaFieldTypeFilter, + filteredIndexedFieldTypeFilter, indexedFieldTypes, isIndexedFilterOpen, scriptedFieldLanguageFilter, scriptedFieldLanguages, isScriptedFieldFilterOpen, - schemaItems, - schemaFieldTypeFilter, isSchemaFilterOpen, openFieldEditor, userEditPermission, + updateFieldFilter, + updateFieldTypeFilter, + updateSchemaFieldTypeFilter, ] ); @@ -469,8 +523,8 @@ export function Tabs({ indexPattern={indexPattern} fieldFilter={fieldFilter} fieldWildcardMatcher={fieldWildcardMatcherDecorated} - indexedFieldTypeFilter={indexedFieldTypeFilter} - schemaFieldTypeFilter={schemaFieldTypeFilter} + indexedFieldTypeFilter={filteredIndexedFieldTypeFilter} + schemaFieldTypeFilter={filteredSchemaFieldTypeFilter} helpers={{ editField: openFieldEditor, deleteField, @@ -547,8 +601,8 @@ export function Tabs({ getFilterSection, history, indexPattern, - indexedFieldTypeFilter, - schemaFieldTypeFilter, + filteredIndexedFieldTypeFilter, + filteredSchemaFieldTypeFilter, refreshFilters, scriptedFieldLanguageFilter, saveIndexPattern, @@ -583,20 +637,41 @@ export function Tabs({ const [selectedTabId, setSelectedTabId] = useState(euiTabs[0].id); useEffect(() => { - const { startSyncingState, stopSyncingState, setCurrentTab, getCurrentTab } = - createEditIndexPatternPageStateContainer({ - useHashedUrl: uiSettings.get('state:storeInSessionStorage'), - defaultTab: TAB_INDEXED_FIELDS, - }); + const { + startSyncingState, + stopSyncingState, + setCurrentTab, + setCurrentFieldTypes, + setCurrentFieldFilter, + setCurrentSchemaFieldTypes, + stateContainer, + } = createEditIndexPatternPageStateContainer({ + useHashedUrl: uiSettings.get('state:storeInSessionStorage'), + defaultTab: TAB_INDEXED_FIELDS, + }); startSyncingState(); setSyncingStateFunc({ setCurrentTab, - getCurrentTab, + setCurrentFieldTypes, + setCurrentFieldFilter, + setCurrentSchemaFieldTypes, + }); + + setSelectedTabId(stateContainer.selectors.tab()); + setIndexedFieldTypeFilter((currentValue) => stateContainer.selectors.fieldTypes() ?? []); + setSchemaFieldTypeFilter((currentValue) => stateContainer.selectors.schemaFieldTypes() ?? []); + setFieldFilter((currentValue) => stateContainer.selectors.fieldFilter() ?? ''); + + const stateSubscription = stateContainer.state$.subscribe(() => { + setSelectedTabId(stateContainer.selectors.tab()); + setIndexedFieldTypeFilter((currentValue) => stateContainer.selectors.fieldTypes() ?? []); + setSchemaFieldTypeFilter((currentValue) => stateContainer.selectors.schemaFieldTypes() ?? []); + setFieldFilter((currentValue) => stateContainer.selectors.fieldFilter() ?? ''); }); - setSelectedTabId(getCurrentTab()); return () => { + stateSubscription.unsubscribe(); stopSyncingState(); }; }, [uiSettings]); @@ -605,10 +680,7 @@ export function Tabs({ tab.id === selectedTabId)} - onTabClick={(tab) => { - setSelectedTabId(tab.id); - syncingStateFunc.setCurrentTab?.(tab.id); - }} + onTabClick={updateTab} /> ); -} +}; diff --git a/src/plugins/data_views/common/data_views/__snapshots__/data_view.test.ts.snap b/src/plugins/data_views/common/data_views/__snapshots__/data_view.test.ts.snap index 2edfe79aec9baf..dcac963b3a7b90 100644 --- a/src/plugins/data_views/common/data_views/__snapshots__/data_view.test.ts.snap +++ b/src/plugins/data_views/common/data_views/__snapshots__/data_view.test.ts.snap @@ -233,6 +233,14 @@ Object { }, "custom_user_field": Object { "aggregatable": true, + "conflictDescriptions": Object { + "keyword": Array [ + "index_a", + ], + "long": Array [ + "index_b", + ], + }, "count": 0, "esTypes": Array [ "conflict", diff --git a/src/plugins/data_views/common/field.stub.ts b/src/plugins/data_views/common/field.stub.ts index bf8abd790fe686..afca4bcdd17fa3 100644 --- a/src/plugins/data_views/common/field.stub.ts +++ b/src/plugins/data_views/common/field.stub.ts @@ -344,6 +344,7 @@ export const stubLogstashFieldSpecMap: Record = { name: 'custom_user_field', type: 'conflict', esTypes: ['conflict'], + conflictDescriptions: { keyword: ['index_a'], long: ['index_b'] }, aggregatable: true, searchable: true, count: 0, diff --git a/src/plugins/discover/kibana.jsonc b/src/plugins/discover/kibana.jsonc index 4a46dd14d689fd..308e6cda10036b 100644 --- a/src/plugins/discover/kibana.jsonc +++ b/src/plugins/discover/kibana.jsonc @@ -37,7 +37,6 @@ "triggersActionsUi", "savedObjectsTaggingOss", "lens", - "serverless", "noDataPage", "globalSearch" ], diff --git a/src/plugins/discover/public/application/context/context_app_content.test.tsx b/src/plugins/discover/public/application/context/context_app_content.test.tsx index f6c87772ec9132..f55fdd448df52f 100644 --- a/src/plugins/discover/public/application/context/context_app_content.test.tsx +++ b/src/plugins/discover/public/application/context/context_app_content.test.tsx @@ -72,6 +72,7 @@ describe('ContextAppContent test', () => { isLegacy: isLegacy ?? true, setAppState: () => {}, addFilter: () => {}, + interceptedWarnings: [], } as unknown as ContextAppContentProps; const component = mountWithIntl( diff --git a/src/plugins/discover/public/application/context/context_app_content.tsx b/src/plugins/discover/public/application/context/context_app_content.tsx index e1ccf1606d07ee..098f789be1a6f4 100644 --- a/src/plugins/discover/public/application/context/context_app_content.tsx +++ b/src/plugins/discover/public/application/context/context_app_content.tsx @@ -15,7 +15,10 @@ import { SortDirection } from '@kbn/data-plugin/public'; import type { SortOrder } from '@kbn/saved-search-plugin/public'; import { CellActionsProvider } from '@kbn/cell-actions'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { type SearchResponseWarning, SearchResponseWarnings } from '@kbn/search-response-warnings'; +import { + type SearchResponseWarning, + SearchResponseWarningsCallout, +} from '@kbn/search-response-warnings'; import { CONTEXT_STEP_SETTING, DOC_HIDE_TIME_COLUMN_SETTING, @@ -50,7 +53,7 @@ export interface ContextAppContentProps { anchorStatus: LoadingStatus; predecessorsStatus: LoadingStatus; successorsStatus: LoadingStatus; - interceptedWarnings: SearchResponseWarning[] | undefined; + interceptedWarnings: SearchResponseWarning[]; useNewFieldsApi: boolean; isLegacy: boolean; setAppState: (newState: Partial) => void; @@ -148,13 +151,9 @@ export function ContextAppContent({ return ( - {!!interceptedWarnings?.length && ( + {interceptedWarnings.length && ( <> - + )} diff --git a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx index 774d47d577a6d9..bf01e2a7b66697 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_documents.tsx @@ -20,7 +20,7 @@ import { DataView } from '@kbn/data-views-plugin/public'; import { SortOrder } from '@kbn/saved-search-plugin/public'; import { CellActionsProvider } from '@kbn/cell-actions'; import type { DataTableRecord } from '@kbn/discover-utils/types'; -import { SearchResponseWarnings } from '@kbn/search-response-warnings'; +import { SearchResponseWarningsCallout } from '@kbn/search-response-warnings'; import { DataLoadingState, useColumns, @@ -277,13 +277,7 @@ function DiscoverDocumentsComponent({ textBasedQueryColumns={documents?.textBasedQueryColumns} selectedColumns={currentColumns} /> - {!!documentState.interceptedWarnings?.length && ( - - )} + ), [ diff --git a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx index 4d5655c012e14d..6461603609903e 100644 --- a/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx +++ b/src/plugins/discover/public/application/main/components/layout/discover_layout.tsx @@ -54,6 +54,7 @@ import { DiscoverHistogramLayout } from './discover_histogram_layout'; import { ErrorCallout } from '../../../../components/common/error_callout'; import { addLog } from '../../../../utils/add_log'; import { DiscoverResizableLayout } from './discover_resizable_layout'; +import { ESQLTechPreviewCallout } from './esql_tech_preview_callout'; const SidebarMemoized = React.memo(DiscoverSidebarResponsive); const TopNavMemoized = React.memo(DiscoverTopNav); @@ -73,6 +74,7 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { history, spaces, inspector, + docLinks, } = useDiscoverServices(); const { euiTheme } = useEuiTheme(); const pageBackgroundColor = useEuiBackgroundColor('plain'); @@ -206,6 +208,8 @@ export function DiscoverLayout({ stateContainer }: DiscoverLayoutProps) { return ( <> + {/* Temporarily display a tech preview callout for ES|QL*/} + {isPlainRecord && } { + const [hideCallout, setHideCallout] = useLocalStorage(ESQL_TECH_PREVIEW_CALLOUT, false); + + const onDismiss = useCallback(() => { + setHideCallout(true); + }, [setHideCallout]); + + if (hideCallout) { + return null; + } + + return ( + + + + ), + }} + /> + } + color="primary" + iconType="beaker" + onDismiss={onDismiss} + size="s" + /> + ); +}; diff --git a/src/plugins/discover/public/application/main/components/no_results/no_results.tsx b/src/plugins/discover/public/application/main/components/no_results/no_results.tsx index 86f73e18ca4d00..cf20a679d95680 100644 --- a/src/plugins/discover/public/application/main/components/no_results/no_results.tsx +++ b/src/plugins/discover/public/application/main/components/no_results/no_results.tsx @@ -10,7 +10,7 @@ import React from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import type { DataView } from '@kbn/data-views-plugin/common'; import type { AggregateQuery, Filter, Query } from '@kbn/es-query'; -import { SearchResponseWarnings } from '@kbn/search-response-warnings'; +import { SearchResponseWarningsEmptyPrompt } from '@kbn/search-response-warnings'; import { NoResultsSuggestions } from './no_results_suggestions'; import type { DiscoverStateContainer } from '../../services/discover_state'; import { useDataState } from '../../hooks/use_data_state'; @@ -37,13 +37,7 @@ export function DiscoverNoResults({ const interceptedWarnings = useDataState(documents$).interceptedWarnings; if (interceptedWarnings?.length) { - return ( - - ); + return ; } return ( diff --git a/src/plugins/discover/public/build_services.ts b/src/plugins/discover/public/build_services.ts index b903d2485bdc4c..da82df24e184f4 100644 --- a/src/plugins/discover/public/build_services.ts +++ b/src/plugins/discover/public/build_services.ts @@ -52,7 +52,6 @@ import type { UiActionsStart } from '@kbn/ui-actions-plugin/public'; import type { SettingsStart } from '@kbn/core-ui-settings-browser'; import type { ContentClient } from '@kbn/content-management-plugin/public'; import { memoize } from 'lodash'; -import type { ServerlessPluginStart } from '@kbn/serverless/public'; import type { NoDataPagePluginStart } from '@kbn/no-data-page-plugin/public'; import { getHistory } from './kibana_services'; import { DiscoverStartPlugins } from './plugin'; @@ -111,7 +110,6 @@ export interface DiscoverServices { lens: LensPublicStart; uiActions: UiActionsStart; contentClient: ContentClient; - serverless?: ServerlessPluginStart; noDataPage?: NoDataPagePluginStart; } @@ -172,7 +170,6 @@ export const buildServices = memoize(function ( lens: plugins.lens, uiActions: plugins.uiActions, contentClient: plugins.contentManagement.client, - serverless: plugins.serverless, noDataPage: plugins.noDataPage, }; }); diff --git a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx index d1ff933ecad8f5..d8c43fd8dedfe2 100644 --- a/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx +++ b/src/plugins/discover/public/components/discover_grid_flyout/discover_grid_flyout.test.tsx @@ -8,6 +8,7 @@ import React from 'react'; import { findTestSubject } from '@elastic/eui/lib/test'; +import { EuiFlexItem } from '@elastic/eui'; import { mountWithIntl } from '@kbn/test-jest-helpers'; import type { Query, AggregateQuery } from '@kbn/es-query'; import { DiscoverGridFlyout, DiscoverGridFlyoutProps } from './discover_grid_flyout'; @@ -24,7 +25,6 @@ import { ReactWrapper } from 'enzyme'; import { setUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/plugin'; import { mockUnifiedDocViewerServices } from '@kbn/unified-doc-viewer-plugin/public/__mocks__'; import { FlyoutCustomization, useDiscoverCustomization } from '../../customizations'; -import { EuiFlexItem } from '@elastic/eui'; const mockFlyoutCustomization: FlyoutCustomization = { id: 'flyout', @@ -69,6 +69,9 @@ describe('Discover flyout', function () { }, contextLocator: { getRedirectUrl: jest.fn(() => 'mock-context-redirect-url') }, singleDocLocator: { getRedirectUrl: jest.fn(() => 'mock-doc-redirect-url') }, + toastNotifications: { + addSuccess: jest.fn(), + }, } as unknown as DiscoverServices; setUnifiedDocViewerServices(mockUnifiedDocViewerServices); @@ -103,11 +106,12 @@ describe('Discover flyout', function () { const component = mountWithIntl(); await waitNextUpdate(component); - return { component, props }; + return { component, props, services }; }; beforeEach(() => { mockFlyoutCustomization.actions.defaultActions = undefined; + mockFlyoutCustomization.Content = undefined; jest.clearAllMocks(); (useDiscoverCustomization as jest.Mock).mockImplementation(() => mockFlyoutCustomization); @@ -226,44 +230,98 @@ describe('Discover flyout', function () { expect(flyoutTitle.text()).toBe('Expanded row'); }); - describe('when customizations actions exists', () => { - it('should display actions added by getActionItems', async () => { - mockFlyoutCustomization.actions = { - getActionItems: jest.fn(() => [ - { - id: 'action-item-1', - enabled: true, - Content: () => Action 1, - }, - { - id: 'action-item-2', - enabled: true, - Content: () => Action 2, + describe('with applied customizations', () => { + describe('when actions are customized', () => { + it('should display actions added by getActionItems', async () => { + mockFlyoutCustomization.actions = { + getActionItems: jest.fn(() => [ + { + id: 'action-item-1', + enabled: true, + Content: () => Action 1, + }, + { + id: 'action-item-2', + enabled: true, + Content: () => Action 2, + }, + ]), + }; + + const { component } = await mountComponent({}); + + const action1 = findTestSubject(component, 'customActionItem1'); + const action2 = findTestSubject(component, 'customActionItem2'); + + expect(action1.text()).toBe('Action 1'); + expect(action2.text()).toBe('Action 2'); + }); + + it('should allow disabling default actions', async () => { + mockFlyoutCustomization.actions = { + defaultActions: { + viewSingleDocument: { disabled: true }, + viewSurroundingDocument: { disabled: true }, }, - ]), - }; + }; - const { component } = await mountComponent({}); + const { component } = await mountComponent({}); - const action1 = findTestSubject(component, 'customActionItem1'); - const action2 = findTestSubject(component, 'customActionItem2'); - - expect(action1.text()).toBe('Action 1'); - expect(action2.text()).toBe('Action 2'); + const singleDocumentView = findTestSubject(component, 'docTableRowAction'); + expect(singleDocumentView.length).toBeFalsy(); + }); }); - it('should allow disabling default actions', async () => { - mockFlyoutCustomization.actions = { - defaultActions: { - viewSingleDocument: { disabled: true }, - viewSurroundingDocument: { disabled: true }, - }, - }; + describe('when content is customized', () => { + it('should display the component passed to the Content customization', async () => { + mockFlyoutCustomization.Content = () => ( + Custom content + ); + + const { component } = await mountComponent({}); + + const customContent = findTestSubject(component, 'flyoutCustomContent'); + + expect(customContent.text()).toBe('Custom content'); + }); + + it('should provide a doc property to display details about the current document overview', async () => { + mockFlyoutCustomization.Content = ({ doc }) => { + return ( + {doc.flattened.message as string} + ); + }; + + const { component } = await mountComponent({}); + + const customContent = findTestSubject(component, 'flyoutCustomContent'); + + expect(customContent.text()).toBe('test1'); + }); + + it('should provide an actions prop collection to optionally update the grid content', async () => { + mockFlyoutCustomization.Content = ({ actions }) => ( + <> +
); diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/common/popover.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/common/popover.tsx index cec9826d00cf73..b6865a10c270bd 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/common/popover.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/common/popover.tsx @@ -44,6 +44,7 @@ export const Popover = ({ closePopover={closePopover} repositionOnScroll anchorPosition="upCenter" + panelStyle={{ maxWidth: 350 }} > {children} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx index 107cbfdb7aa682..a62a797ecfdefa 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/logs/logs.tsx @@ -18,7 +18,7 @@ import { findInventoryFields } from '../../../../../common/inventory_models'; import { InfraLoadingPanel } from '../../../loading'; import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props'; import { useDataViewsProviderContext } from '../../hooks/use_data_views'; -import { useDateRangeProviderContext } from '../../hooks/use_date_range'; +import { useDatePickerContext } from '../../hooks/use_date_picker'; import { useAssetDetailsUrlState } from '../../hooks/use_asset_details_url_state'; import { useIntersectingState } from '../../hooks/use_intersecting_state'; @@ -26,7 +26,7 @@ const TEXT_QUERY_THROTTLE_INTERVAL_MS = 500; export const Logs = () => { const ref = useRef(null); - const { getDateRangeInTimestamp, dateRange, autoRefresh } = useDateRangeProviderContext(); + const { getDateRangeInTimestamp, dateRange, autoRefresh } = useDatePickerContext(); const [urlState, setUrlState] = useAssetDetailsUrlState(); const { asset } = useAssetDetailsRenderPropsContext(); const { logs } = useDataViewsProviderContext(); diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.test.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.test.tsx index d62557654ad6c8..b1e9494ce9b56b 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.test.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.test.tsx @@ -13,9 +13,26 @@ import { render } from '@testing-library/react'; import { I18nProvider } from '@kbn/i18n-react'; import { EuiThemeProvider } from '@kbn/kibana-react-plugin/common'; import { ContextProviders } from '../../context_providers'; +import { coreMock } from '@kbn/core/public/mocks'; +import { dataPluginMock } from '@kbn/data-plugin/public/mocks'; +import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; jest.mock('../../../../containers/metrics_source'); jest.mock('../../hooks/use_metadata'); +jest.mock('../../../../hooks/use_kibana'); + +const useKibanaMock = useKibanaContextForPlugin as jest.MockedFunction< + typeof useKibanaContextForPlugin +>; + +const mockUseKibana = () => { + useKibanaMock.mockReturnValue({ + services: { + ...coreMock.createStart(), + data: dataPluginMock.createStartContract(), + }, + } as unknown as ReturnType); +}; const renderHostMetadata = () => render( @@ -43,6 +60,14 @@ const renderHostMetadata = () => { wrapper: EuiThemeProvider } ); +beforeEach(() => { + mockUseKibana(); +}); + +afterEach(() => { + jest.clearAllMocks(); +}); + describe('Single Host Metadata (Hosts View)', () => { const mockUseMetadata = (props: any = {}) => { const data = { diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx index ef2b0a97ba476d..02168778c36761 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/metadata/metadata.tsx @@ -9,7 +9,7 @@ import React, { useCallback, useMemo } from 'react'; import { EuiHorizontalRule } from '@elastic/eui'; import { Table } from './table'; import { getAllFields } from './utils'; -import { useMetadataStateProviderContext } from '../../hooks/use_metadata_state'; +import { useMetadataStateContext } from '../../hooks/use_metadata_state'; import { MetadataExplanationMessage } from '../../components/metadata_explanation'; import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props'; import { useAssetDetailsUrlState } from '../../hooks/use_asset_details_url_state'; @@ -27,7 +27,7 @@ export const Metadata = () => { metadata, loading: metadataLoading, error: fetchMetadataError, - } = useMetadataStateProviderContext(); + } = useMetadataStateContext(); const { showActionsColumn = false } = overrides?.metadata ?? {}; const fields = useMemo(() => getAllFields(metadata), [metadata]); diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/osquery/osquery.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/osquery/osquery.tsx index 8f3b6f91b315b5..95d6ad0fcc4038 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/osquery/osquery.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/osquery/osquery.tsx @@ -9,10 +9,10 @@ import { EuiSkeletonText } from '@elastic/eui'; import React, { useRef } from 'react'; import { usePluginConfig } from '../../../../containers/plugin_config_context'; import { useKibanaContextForPlugin } from '../../../../hooks/use_kibana'; -import { useMetadataStateProviderContext } from '../../hooks/use_metadata_state'; +import { useMetadataStateContext } from '../../hooks/use_metadata_state'; export const Osquery = () => { - const { metadata, loading } = useMetadataStateProviderContext(); + const { metadata, loading } = useMetadataStateContext(); const agentId = useRef(undefined); // When a host has multiple agents reporting metrics, it's possible that one of them may not report an agent id. diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx index 54305b7212a559..f586aeaab7630f 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/kpis/kpi.tsx @@ -11,8 +11,7 @@ import { TimeRange } from '@kbn/es-query'; import { LensChart, TooltipContent } from '../../../../lens'; import { AVERAGE_SUBTITLE, type KPIChartProps } from '../../../../../common/visualizations'; import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; - -import { useDateRangeProviderContext } from '../../../hooks/use_date_range'; +import { useLoadingStateContext } from '../../../hooks/use_loading_state'; export const Kpi = ({ id, @@ -29,7 +28,7 @@ export const Kpi = ({ assetName: string; dateRange: TimeRange; }) => { - const { refreshTs } = useDateRangeProviderContext(); + const { searchSessionId } = useLoadingStateContext(); const filters = useMemo(() => { return [ buildCombinedHostsFilter({ @@ -48,13 +47,13 @@ export const Kpi = ({ dataView={dataView} dateRange={dateRange} layers={layers} - lastReloadRequestTime={refreshTs} height={height} filters={filters} title={title} subtitle={AVERAGE_SUBTITLE} toolTip={tooltipContent} visualizationType="lnsMetric" + searchSessionId={searchSessionId} disableTriggers hidePanelTitles /> diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx index ab096e83378748..72d7f27c7dc48a 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/chart.tsx @@ -11,9 +11,10 @@ import type { TimeRange } from '@kbn/es-query'; import { buildCombinedHostsFilter } from '../../../../../utils/filters/build'; import { type BrushEndArgs, LensChart, type OnFilterEvent } from '../../../../lens'; import { METRIC_CHART_HEIGHT } from '../../../constants'; -import { useDateRangeProviderContext } from '../../../hooks/use_date_range'; +import { useDatePickerContext } from '../../../hooks/use_date_picker'; import { extractRangeFromChartFilterEvent } from './chart_utils'; import type { XYConfig } from '../../../../../common/visualizations'; +import { useLoadingStateContext } from '../../../hooks/use_loading_state'; export interface ChartProps extends XYConfig { visualOptions?: XYVisualOptions; @@ -39,7 +40,8 @@ export const Chart = ({ assetName, ...props }: ChartProps) => { - const { setDateRange, refreshTs } = useDateRangeProviderContext(); + const { setDateRange } = useDatePickerContext(); + const { searchSessionId } = useLoadingStateContext(); const dataView = useMemo(() => { return dataViewOrigin === 'metrics' ? metricsDataView : logsDataView; @@ -89,11 +91,11 @@ export const Chart = ({ dateRange={dateRange} height={METRIC_CHART_HEIGHT} visualOptions={visualOptions} + searchSessionId={searchSessionId} layers={layers} filters={filters} title={title} overrides={overrides} - lastReloadRequestTime={refreshTs} visualizationType="lnsXY" onBrushEnd={handleBrushEnd} onFilter={handleFilter} diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx index d0bfd585e5080d..1050ff72a246c4 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_grid.tsx @@ -12,7 +12,7 @@ import { type XYConfig, XY_MISSING_VALUE_DOTTED_LINE_CONFIG, } from '../../../../../common/visualizations'; -import { useMetadataStateProviderContext } from '../../../hooks/use_metadata_state'; +import { useMetadataStateContext } from '../../../hooks/use_metadata_state'; import { Chart } from './chart'; interface Props { @@ -34,7 +34,7 @@ export const MetricsGrid = ({ charts, ...props }: Props) => { - const { metadata } = useMetadataStateProviderContext(); + const { metadata } = useMetadataStateContext(); const chartsToRender = useMemo( () => diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx index beaa4f8c4e8ce6..f6baa4038c2309 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/metrics/metrics_section.tsx @@ -15,7 +15,7 @@ import { MetricsSectionTitle, KubernetesMetricsSectionTitle, } from '../../../components/section_titles'; -import { useMetadataStateProviderContext } from '../../../hooks/use_metadata_state'; +import { useMetadataStateContext } from '../../../hooks/use_metadata_state'; import { MetricsGrid } from './metrics_grid'; interface Props { @@ -85,7 +85,7 @@ const Section = ({ children: React.ReactNode; }) => { const Title = title; - const { metadata } = useMetadataStateProviderContext(); + const { metadata } = useMetadataStateContext(); const shouldRender = useMemo( () => diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx index 5ec6ce182f55af..83cf114d43b91f 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/overview/overview.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import React, { useMemo, useRef } from 'react'; +import React, { useRef } from 'react'; import { EuiFlexGroup, EuiFlexItem } from '@elastic/eui'; import { MetadataSummaryList, @@ -15,39 +15,39 @@ import { AlertsSummaryContent } from './alerts'; import { KPIGrid } from './kpis/kpi_grid'; import { MetricsSection, MetricsSectionCompact } from './metrics/metrics_section'; import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props'; -import { useMetadataStateProviderContext } from '../../hooks/use_metadata_state'; +import { useMetadataStateContext } from '../../hooks/use_metadata_state'; import { useDataViewsProviderContext } from '../../hooks/use_data_views'; -import { useDateRangeProviderContext } from '../../hooks/use_date_range'; +import { useDatePickerContext } from '../../hooks/use_date_picker'; import { SectionSeparator } from './section_separator'; import { MetadataErrorCallout } from '../../components/metadata_error_callout'; import { useIntersectingState } from '../../hooks/use_intersecting_state'; export const Overview = () => { const ref = useRef(null); - const { getParsedDateRange } = useDateRangeProviderContext(); + const { dateRange } = useDatePickerContext(); const { asset, renderMode } = useAssetDetailsRenderPropsContext(); const { metadata, loading: metadataLoading, error: fetchMetadataError, - } = useMetadataStateProviderContext(); + } = useMetadataStateContext(); + const { logs, metrics } = useDataViewsProviderContext(); - const parsedDateRange = useMemo(() => getParsedDateRange(), [getParsedDateRange]); const isFullPageView = renderMode.mode !== 'flyout'; - const state = useIntersectingState(ref, { parsedDateRange }); + const state = useIntersectingState(ref, { dateRange }); const metricsSection = isFullPageView ? ( ) : ( { return ( - + {fetchMetadataError && !metadataLoading ? : metadataSummarySection} @@ -76,7 +72,7 @@ export const Overview = () => { diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/process_row_charts.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/process_row_charts.tsx index 47c4a6102798ed..dfb1b204c4b515 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/process_row_charts.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/process_row_charts.tsx @@ -32,6 +32,7 @@ import { createFormatter } from '../../../../../common/formatters'; import { MetricsExplorerAggregation } from '../../../../../common/http_api'; import { Process } from './types'; import { MetricsExplorerChartType } from '../../../../../common/metrics_explorer_views/types'; +import { useRequestObservable } from '../../hooks/use_request_observable'; import { MetricNotAvailableExplanationTooltip } from '../../components/metric_not_available_explanation'; interface Props { @@ -65,7 +66,8 @@ const EmptyChartPlaceholder = ({ metricName }: { metricName: string }) => ( ); export const ProcessRowCharts = ({ command, hasCpuData, hasMemoryData }: Props) => { - const { loading, error, response } = useProcessListRowChart(command); + const { request$ } = useRequestObservable(); + const { loading, error, response } = useProcessListRowChart(command, request$); const isLoading = loading || !response; diff --git a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx index 8881c30e00e057..fce43bdc4678fd 100644 --- a/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/tabs/processes/processes.tsx @@ -26,11 +26,12 @@ import { SummaryTable } from './summary_table'; import { SortBy, useProcessList, ProcessListContextProvider } from '../../hooks/use_process_list'; import { getFieldByType } from '../../../../../common/inventory_models'; import { useAssetDetailsRenderPropsContext } from '../../hooks/use_asset_details_render_props'; -import { useDateRangeProviderContext } from '../../hooks/use_date_range'; +import { useDatePickerContext } from '../../hooks/use_date_picker'; import { ProcessesExplanationMessage } from '../../components/processes_explanation'; import { useAssetDetailsUrlState } from '../../hooks/use_asset_details_url_state'; import { TopProcessesTooltip } from '../../components/top_processes_tooltip'; import { useIntersectingState } from '../../hooks/use_intersecting_state'; +import { useRequestObservable } from '../../hooks/use_request_observable'; const options = Object.entries(STATE_NAMES).map(([value, view]: [string, string]) => ({ value, @@ -39,7 +40,8 @@ const options = Object.entries(STATE_NAMES).map(([value, view]: [string, string] export const Processes = () => { const ref = useRef(null); - const { getDateRangeInTimestamp } = useDateRangeProviderContext(); + const { request$ } = useRequestObservable(); + const { getDateRangeInTimestamp } = useDatePickerContext(); const [urlState, setUrlState] = useAssetDetailsUrlState(); const { asset } = useAssetDetailsRenderPropsContext(); const [searchText, setSearchText] = useState(urlState?.processSearch ?? ''); @@ -68,7 +70,13 @@ export const Processes = () => { error, response, makeRequest: reload, - } = useProcessList(hostTerm, state.currentTimestamp, sortBy, parseSearchString(searchText)); + } = useProcessList( + hostTerm, + state.currentTimestamp, + sortBy, + parseSearchString(searchText), + request$ + ); const debouncedSearchOnChange = useMemo(() => { return debounce<(queryText: string) => void>((queryText) => { diff --git a/x-pack/plugins/infra/public/components/asset_details/template/page.tsx b/x-pack/plugins/infra/public/components/asset_details/template/page.tsx index b54738514522c7..260114bb8b11f2 100644 --- a/x-pack/plugins/infra/public/components/asset_details/template/page.tsx +++ b/x-pack/plugins/infra/public/components/asset_details/template/page.tsx @@ -15,7 +15,7 @@ import { InfraLoadingPanel } from '../../loading'; import { ASSET_DETAILS_PAGE_COMPONENT_NAME } from '../constants'; import { Content } from '../content/content'; import { useAssetDetailsRenderPropsContext } from '../hooks/use_asset_details_render_props'; -import { useMetadataStateProviderContext } from '../hooks/use_metadata_state'; +import { useMetadataStateContext } from '../hooks/use_metadata_state'; import { usePageHeader } from '../hooks/use_page_header'; import { useTabSwitcherContext } from '../hooks/use_tab_switcher'; import { ContentTemplateProps } from '../types'; @@ -23,7 +23,7 @@ import { getIntegrationsAvailable } from '../utils'; export const Page = ({ tabs = [], links = [] }: ContentTemplateProps) => { const { loading } = useAssetDetailsRenderPropsContext(); - const { metadata, loading: metadataLoading } = useMetadataStateProviderContext(); + const { metadata, loading: metadataLoading } = useMetadataStateContext(); const { rightSideItems, tabEntries, breadcrumbs } = usePageHeader(tabs, links); const { asset } = useAssetDetailsRenderPropsContext(); const { actionMenuHeight } = useKibanaHeader(); diff --git a/x-pack/plugins/infra/public/components/lens/lens_chart.tsx b/x-pack/plugins/infra/public/components/lens/lens_chart.tsx index 613cfec5665724..ac8a40d7d580fd 100644 --- a/x-pack/plugins/infra/public/components/lens/lens_chart.tsx +++ b/x-pack/plugins/infra/public/components/lens/lens_chart.tsx @@ -20,6 +20,7 @@ export type LensChartProps = UseLensAttributesParams & BaseChartProps & Pick & { toolTip?: React.ReactElement; + searchSessionId?: string; }; export const LensChart = React.memo( @@ -35,6 +36,7 @@ export const LensChart = React.memo( onFilter, overrides, toolTip, + searchSessionId, disableTriggers = false, height = MIN_HEIGHT, loading = false, @@ -48,6 +50,7 @@ export const LensChart = React.memo( timeRange: dateRange, query, filters, + searchSessionId, }); const lens = ( @@ -59,12 +62,12 @@ export const LensChart = React.memo( extraActions={extraActions} filters={filters} hidePanelTitles={hidePanelTitles} - lastReloadRequestTime={lastReloadRequestTime} loading={isLoading} style={{ height }} query={query} overrides={overrides} onBrushEnd={onBrushEnd} + searchSessionId={searchSessionId} onFilter={onFilter} /> ); diff --git a/x-pack/plugins/infra/public/components/lens/lens_wrapper.tsx b/x-pack/plugins/infra/public/components/lens/lens_wrapper.tsx index d5c70be73033af..01d409fc9a1ac9 100644 --- a/x-pack/plugins/infra/public/components/lens/lens_wrapper.tsx +++ b/x-pack/plugins/infra/public/components/lens/lens_wrapper.tsx @@ -4,24 +4,21 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import React, { useEffect, useState, useRef, useCallback, useMemo } from 'react'; - +import React, { useEffect, useState, useRef, useCallback } from 'react'; import { ViewMode } from '@kbn/embeddable-plugin/public'; -import type { TimeRange } from '@kbn/es-query'; import { TypedLensByValueInput } from '@kbn/lens-plugin/public'; import { css } from '@emotion/react'; import { useEuiTheme } from '@elastic/eui'; import { LensAttributes } from '@kbn/lens-embeddable-utils'; import { useKibanaContextForPlugin } from '../../hooks/use_kibana'; import { ChartLoadingProgress, ChartPlaceholder } from './chart_placeholder'; -import { parseDateRange } from '../../utils/datemath'; import type { LensWrapperProps } from './types'; export const LensWrapper = ({ attributes, dateRange, filters, - lastReloadRequestTime, + searchSessionId, loading = false, onLoad, query, @@ -35,8 +32,8 @@ export const LensWrapper = ({ attributes, dateRange, filters, - lastReloadRequestTime, query, + searchSessionId, }); const ref = useRef(null); @@ -64,8 +61,8 @@ export const LensWrapper = ({ attributes, dateRange, filters, - lastReloadRequestTime, query, + searchSessionId, }); } }, [ @@ -73,8 +70,8 @@ export const LensWrapper = ({ dateRange, filters, intersectionObserverEntry?.isIntersecting, - lastReloadRequestTime, query, + searchSessionId, ]); const handleOnLoad = useCallback( @@ -82,6 +79,7 @@ export const LensWrapper = ({ if (!embeddableLoaded) { setEmbeddableLoaded(true); } + if (onLoad) { onLoad(isLoading); } @@ -89,13 +87,6 @@ export const LensWrapper = ({ [embeddableLoaded, onLoad] ); - const parsedDateRange: TimeRange = useMemo(() => { - const { from = state.dateRange.from, to = state.dateRange.to } = parseDateRange( - state.dateRange - ); - - return { from, to }; - }, [state.dateRange]); const isLoading = loading || !state.attributes; return ( @@ -119,12 +110,12 @@ export const LensWrapper = ({ {isLoading && } diff --git a/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts b/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts index e70e8977027fff..aa5feb4dc0b47f 100644 --- a/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts +++ b/x-pack/plugins/infra/public/hooks/use_lens_attributes.ts @@ -91,7 +91,17 @@ export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesPara ); const openInLensAction = useCallback( - ({ timeRange, query, filters }: { timeRange: TimeRange; filters: Filter[]; query: Query }) => + ({ + timeRange, + query, + filters, + searchSessionId, + }: { + timeRange: TimeRange; + filters: Filter[]; + query: Query; + searchSessionId?: string; + }) => () => { const injectedAttributes = injectFilters({ filters, query }); if (injectedAttributes) { @@ -100,6 +110,7 @@ export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesPara id: '', timeRange, attributes: injectedAttributes, + searchSessionId, }, { openInNewTab: true, @@ -115,12 +126,16 @@ export const useLensAttributes = ({ dataView, ...params }: UseLensAttributesPara timeRange, filters = [], query = { language: 'kuery', query: '' }, + searchSessionId, }: { timeRange: TimeRange; filters?: Filter[]; query?: Query; + searchSessionId?: string; }) => { - const openInLens = getOpenInLensAction(openInLensAction({ timeRange, filters, query })); + const openInLens = getOpenInLensAction( + openInLensAction({ timeRange, filters, query, searchSessionId }) + ); return [openInLens]; }, [openInLensAction] diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx index 24b1ba216d0548..d57f28b6b71ed2 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/kpis/kpi.tsx @@ -16,9 +16,9 @@ import { useHostCountContext } from '../../hooks/use_host_count'; import { useAfterLoadedState } from '../../hooks/use_after_loaded_state'; export const Kpi = ({ id, title, layers, toolTip, height }: KPIChartProps & { height: number }) => { - const { searchCriteria, parsedDateRange } = useUnifiedSearchContext(); + const { searchCriteria } = useUnifiedSearchContext(); const { dataView } = useMetricsDataViewContext(); - const { requestTs, hostNodes, loading: hostsLoading } = useHostsViewContext(); + const { hostNodes, loading: hostsLoading, searchSessionId } = useHostsViewContext(); const { data: hostCountData, isRequestRunning: hostCountLoading } = useHostCountContext(); const shouldUseSearchCriteria = hostNodes.length === 0; @@ -48,10 +48,10 @@ export const Kpi = ({ id, title, layers, toolTip, height }: KPIChartProps & { he // we want it to reload only once the table has finished loading. // attributes passed to useAfterLoadedState don't need to be memoized const { afterLoadedState } = useAfterLoadedState(loading, { - lastReloadRequestTime: requestTs, - dateRange: parsedDateRange, + dateRange: searchCriteria.dateRange, query: shouldUseSearchCriteria ? searchCriteria.query : undefined, filters, + searchSessionId, subtitle, }); @@ -64,11 +64,11 @@ export const Kpi = ({ id, title, layers, toolTip, height }: KPIChartProps & { he dateRange={afterLoadedState.dateRange} filters={afterLoadedState.filters} layers={layers} - lastReloadRequestTime={afterLoadedState.lastReloadRequestTime} loading={loading} height={height} query={afterLoadedState.query} title={title} + searchSessionId={afterLoadedState.searchSessionId} subtitle={afterLoadedState.subtitle} toolTip={tooltipComponent} visualizationType="lnsMetric" diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx index 596f2a70a13e3f..d7af2f06d4b08e 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/components/tabs/metrics/chart.tsx @@ -21,20 +21,20 @@ export interface ChartProps extends AssetXYChartProps { } export const Chart = ({ id, title, layers, visualOptions, overrides }: ChartProps) => { - const { parsedDateRange, searchCriteria } = useUnifiedSearchContext(); + const { searchCriteria } = useUnifiedSearchContext(); const { dataView } = useMetricsDataViewContext(); - const { requestTs, loading } = useHostsViewContext(); + const { loading, searchSessionId } = useHostsViewContext(); const { currentPage } = useHostsTableContext(); const shouldUseSearchCriteria = currentPage.length === 0; - // prevents requestTs and searchCriteria state from reloading the chart + // prevents searchCriteria state from reloading the chart // we want it to reload only once the table has finished loading. // attributes passed to useAfterLoadedState don't need to be memoized const { afterLoadedState } = useAfterLoadedState(loading, { - lastReloadRequestTime: requestTs, - dateRange: parsedDateRange, + dateRange: searchCriteria.dateRange, query: shouldUseSearchCriteria ? searchCriteria.query : undefined, + searchSessionId, }); const filters = useMemo(() => { @@ -58,10 +58,10 @@ export const Chart = ({ id, title, layers, visualOptions, overrides }: ChartProp height={METRIC_CHART_HEIGHT} layers={layers} visualOptions={visualOptions} - lastReloadRequestTime={afterLoadedState.lastReloadRequestTime} loading={loading} filters={filters} query={afterLoadedState.query} + searchSessionId={afterLoadedState.searchSessionId} title={title} overrides={overrides} visualizationType="lnsXY" diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_count.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_count.ts index 5d1f4766a775ac..d261b4ec2e45d1 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_count.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_host_count.ts @@ -22,7 +22,7 @@ export const useHostCount = () => { const { services: { telemetry }, } = useKibanaContextForPlugin(); - const { buildQuery, parsedDateRange } = useUnifiedSearchContext(); + const { buildQuery, searchCriteria } = useUnifiedSearchContext(); const { search: fetchHostCount, requests$ } = useDataSearch({ getRequest: useCallback(() => { @@ -41,9 +41,8 @@ export const useHostCount = () => { { range: { [dataView?.timeFieldName ?? '@timestamp']: { - gte: parsedDateRange.from, - lte: parsedDateRange.to, - format: 'strict_date_optional_time', + gte: searchCriteria.dateRange.from, + lte: searchCriteria.dateRange.to, }, }, }, @@ -73,7 +72,13 @@ export const useHostCount = () => { }, options: { strategy: ES_SEARCH_STRATEGY }, }; - }, [buildQuery, dataView, parsedDateRange, metricAlias]), + }, [ + buildQuery, + dataView?.timeFieldName, + metricAlias, + searchCriteria.dateRange.from, + searchCriteria.dateRange.to, + ]), parseResponses: normalizeDataSearchResponse, }); diff --git a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_view.ts b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_view.ts index 6cf0a0f09de546..e56faa0cc2c1bd 100644 --- a/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_view.ts +++ b/x-pack/plugins/infra/public/pages/metrics/hosts/hooks/use_hosts_view.ts @@ -12,7 +12,7 @@ * 2.0. */ -import { useEffect, useMemo, useRef } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import createContainer from 'constate'; import { BoolQuery } from '@kbn/es-query'; import useAsyncFn from 'react-use/lib/useAsyncFn'; @@ -41,10 +41,11 @@ const BASE_INFRA_METRICS_PATH = '/api/metrics/infra'; export const useHostsView = () => { const { sourceId } = useSourceContext(); const { - services: { http }, + services: { http, data }, } = useKibanaContextForPlugin(); const { buildQuery, parsedDateRange, searchCriteria } = useUnifiedSearchContext(); const abortCtrlRef = useRef(new AbortController()); + const [searchSessionId, setSearchSessionId] = useState(() => data.search.session.start()); const baseRequest = useMemo( () => @@ -73,15 +74,16 @@ export const useHostsView = () => { useEffect(() => { refetch(); - }, [refetch]); + setSearchSessionId(data.search.session.start()); + }, [data.search.session, refetch]); const { value, error, loading } = state; return { - requestTs: baseRequest.requestTs, loading, error, hostNodes: value?.nodes ?? [], + searchSessionId, }; }; @@ -102,7 +104,7 @@ const createInfraMetricsRequest = ({ sourceId: string; dateRange: StringDateRange; limit: number; -}): GetInfraMetricsRequestBodyPayload & { requestTs: number } => ({ +}): GetInfraMetricsRequestBodyPayload => ({ type: 'host', query: esQuery, range: { @@ -112,5 +114,4 @@ const createInfraMetricsRequest = ({ metrics: HOST_TABLE_METRICS, limit, sourceId, - requestTs: Date.now(), }); diff --git a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table.tsx b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table.tsx index 1effc203084c67..25258a1aff1a47 100644 --- a/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table.tsx +++ b/x-pack/plugins/infra/public/pages/metrics/inventory_view/components/ml/anomaly_detection/anomalies_table/anomalies_table.tsx @@ -29,6 +29,7 @@ import { FormattedMessage, FormattedDate } from '@kbn/i18n-react'; import { useLinkProps, useUiTracker } from '@kbn/observability-shared-plugin/public'; import type { TimeRange } from '@kbn/es-query'; import { css } from '@emotion/react'; +import { Subject } from 'rxjs'; import { datemathToEpochMillis } from '../../../../../../../utils/datemath'; import type { SnapshotMetricType } from '../../../../../../../../common/inventory_models/types'; import { useSorting } from '../../../../../../../hooks/use_sorting'; @@ -197,6 +198,8 @@ interface Props { dateRange?: TimeRange; // In case the date picker is managed outside this component hideDatePicker?: boolean; + // subject to watch the completition of the request + request$?: Subject<() => Promise>; } const DEFAULT_DATE_RANGE: TimeRange = { @@ -209,6 +212,7 @@ export const AnomaliesTable = ({ hostName, dateRange = DEFAULT_DATE_RANGE, hideDatePicker = false, + request$, }: Props) => { const [search, setSearch] = useState(''); const trackMetric = useUiTracker({ app: 'infra_metrics' }); @@ -461,9 +465,13 @@ export const AnomaliesTable = ({ useEffect(() => { if (getAnomalies) { - getAnomalies(undefined, search, hostName); + if (request$) { + request$.next(() => getAnomalies(undefined, search, hostName)); + } else { + getAnomalies(undefined, search, hostName); + } } - }, [getAnomalies, search, hostName]); + }, [getAnomalies, hostName, request$, search]); return ( diff --git a/x-pack/plugins/lens/public/datasources/form_based/utils.tsx b/x-pack/plugins/lens/public/datasources/form_based/utils.tsx index f9aecd4726fb92..16c4dbdc047fbb 100644 --- a/x-pack/plugins/lens/public/datasources/form_based/utils.tsx +++ b/x-pack/plugins/lens/public/datasources/form_based/utils.tsx @@ -12,14 +12,17 @@ import type { DocLinksStart, ThemeServiceStart } from '@kbn/core/public'; import { hasUnsupportedDownsampledAggregationFailure } from '@kbn/search-response-warnings'; import type { DatatableUtilitiesService } from '@kbn/data-plugin/common'; import { TimeRange } from '@kbn/es-query'; -import { EuiLink, EuiSpacer, EuiText } from '@elastic/eui'; +import { EuiLink, EuiSpacer } from '@elastic/eui'; import type { DatatableColumn } from '@kbn/expressions-plugin/common'; import { groupBy, escape, uniq, uniqBy } from 'lodash'; import type { Query } from '@kbn/data-plugin/common'; import { SearchRequest } from '@kbn/data-plugin/common'; -import { type SearchResponseWarning, ViewWarningButton } from '@kbn/search-response-warnings'; +import { + type SearchResponseWarning, + SearchResponseWarningsBadgePopoverContent, +} from '@kbn/search-response-warnings'; import { estypes } from '@elastic/elasticsearch'; import { isQueryValid } from '@kbn/visualization-ui-components'; @@ -307,19 +310,10 @@ export function getSearchWarningMessages( displayLocations: [{ id: 'toolbar' }, { id: 'embeddableBadge' }], shortMessage: '', longMessage: (closePopover) => ( - <> - {warning.message} - - { - closePopover(); - warning.openInInspector(); - }} - size="m" - color="primary" - isButtonEmpty={true} - /> - + ), } as UserMessage, ]; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.scss b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.scss index 88ecee001dab1a..3b7dd8049757a0 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.scss +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.scss @@ -11,13 +11,15 @@ } .lnsWorkspaceWarningList__item { - padding: $euiSize; - & + & { border-top: $euiBorderThin; } } +.lnsWorkspaceWarningList__textItem { + padding: $euiSize; +} + .lnsWorkspaceWarningList__description { overflow-wrap: break-word; min-width: 0; diff --git a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.tsx b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.tsx index af4eabda5ffc1c..091944b6601810 100644 --- a/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.tsx +++ b/x-pack/plugins/lens/public/editor_frame_service/editor_frame/workspace_panel/message_list.tsx @@ -113,22 +113,26 @@ export const MessageList = ({ className="lnsWorkspaceWarningList__item" data-test-subj={`lens-message-list-${message.severity}`} > - - - {message.severity === 'error' ? ( - - ) : ( - - )} - - - - {typeof message.longMessage === 'function' - ? message.longMessage(closePopover) - : message.longMessage} - - - + {typeof message.longMessage === 'function' ? ( + message.longMessage(closePopover) + ) : ( + + + {message.severity === 'error' ? ( + + ) : ( + + )} + + + {message.longMessage} + + + )} ))} diff --git a/x-pack/plugins/monitoring/dev_docs/how_to/apm_tracing.md b/x-pack/plugins/monitoring/dev_docs/how_to/apm_tracing.md index de49f7ceef50fe..60ef44294015db 100644 --- a/x-pack/plugins/monitoring/dev_docs/how_to/apm_tracing.md +++ b/x-pack/plugins/monitoring/dev_docs/how_to/apm_tracing.md @@ -23,7 +23,7 @@ For example: ```json { - "user_settings_override_yaml": "elastic.apm.active: true\nelastic.apm.serverUrl: https://\nelastic.apm.secretToken: \nelastic.apm.globalLabels.deploymentId: \nelastic.apm.centralConfig: false\nelastic.apm.breakdownMetrics: false\nelastic.apm.transactionSampleRate: 0.1\nelastic.apm.metricsInterval: 120s\nelastic.apm.captureSpanStackTraces: false" + "user_settings_override_yaml": "elastic.apm.active: true\nelastic.apm.serverUrl: https://\nelastic.apm.secretToken: " } ``` @@ -37,12 +37,6 @@ For on-premise deployments or developers outside Elastic, you can configure an A elastic.apm.active: true elastic.apm.serverUrl: https:// elastic.apm.secretToken: -elastic.apm.globalLabels.deploymentId: -elastic.apm.centralConfig: false -elastic.apm.breakdownMetrics: false -elastic.apm.transactionSampleRate: 0.1 -elastic.apm.metricsInterval: 120s -elastic.apm.captureSpanStackTraces: false ``` When running in ECE you can update `kibana.yml` settings via the ECE web UI under "Edit user setting" for the kibana nodes in the deployment. diff --git a/x-pack/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap b/x-pack/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap index 2e0caa8472fbd0..fbc47109d9be5e 100644 --- a/x-pack/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap +++ b/x-pack/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap @@ -49,21 +49,17 @@ exports[`SetupModeRenderer should render the flyout open 1`] = ` - - , - } + , } - /> - + } + /> @@ -142,21 +138,17 @@ exports[`SetupModeRenderer should render with setup mode enabled 1`] = ` - - , - } + , } - /> - + } + /> diff --git a/x-pack/plugins/monitoring/public/components/renderers/setup_mode.js b/x-pack/plugins/monitoring/public/components/renderers/setup_mode.js index 8119685dc65f6b..5022e71a348f26 100644 --- a/x-pack/plugins/monitoring/public/components/renderers/setup_mode.js +++ b/x-pack/plugins/monitoring/public/components/renderers/setup_mode.js @@ -5,14 +5,7 @@ * 2.0. */ -import { - EuiBottomBar, - EuiFlexGroup, - EuiFlexItem, - EuiIcon, - EuiSpacer, - EuiTextColor, -} from '@elastic/eui'; +import { EuiBottomBar, EuiFlexGroup, EuiFlexItem, EuiIcon, EuiSpacer } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import React, { Fragment } from 'react'; import { withKibana } from '@kbn/kibana-react-plugin/public'; @@ -144,15 +137,13 @@ export class WrappedSetupModeRenderer extends React.Component { - - , - }} - /> - + , + }} + /> diff --git a/x-pack/plugins/observability/public/application/hideable_react_query_dev_tools.tsx b/x-pack/plugins/observability/public/application/hideable_react_query_dev_tools.tsx index 322d8a467ef389..e7109f9d6c42db 100644 --- a/x-pack/plugins/observability/public/application/hideable_react_query_dev_tools.tsx +++ b/x-pack/plugins/observability/public/application/hideable_react_query_dev_tools.tsx @@ -6,6 +6,7 @@ */ import React, { useState } from 'react'; +import { i18n } from '@kbn/i18n'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import { EuiButtonIcon } from '@elastic/eui'; @@ -20,7 +21,10 @@ export function HideableReactQueryDevTools() { color="primary" style={{ zIndex: 99999, position: 'fixed', bottom: '40px', left: '40px' }} onClick={() => setIsHidden(!isHidden)} - aria-label="Hide react query" + aria-label={i18n.translate( + 'xpack.observability.hideableReactQueryDevTools.euiButtonIcon.hideReactQueryLabel', + { defaultMessage: 'Hide react query' } + )} />
diff --git a/x-pack/plugins/observability/public/components/burn_rate_rule_editor/burn_rate_rule_editor.tsx b/x-pack/plugins/observability/public/components/burn_rate_rule_editor/burn_rate_rule_editor.tsx index 3aa7651320bc3c..fc3e0bf71452b7 100644 --- a/x-pack/plugins/observability/public/components/burn_rate_rule_editor/burn_rate_rule_editor.tsx +++ b/x-pack/plugins/observability/public/components/burn_rate_rule_editor/burn_rate_rule_editor.tsx @@ -95,7 +95,11 @@ export function BurnRateRuleEditor(props: Props) { return ( <> -
Choose a SLO to monitor
+
+ {i18n.translate('xpack.observability.burnRateRuleEditor.h5.chooseASLOToMonitorLabel', { + defaultMessage: 'Choose a SLO to monitor', + })} +
@@ -115,7 +119,11 @@ export function BurnRateRuleEditor(props: Props) { )} -
Define multiple burn rate windows
+
+ {i18n.translate('xpack.observability.burnRateRuleEditor.h5.defineMultipleBurnRateLabel', { + defaultMessage: 'Define multiple burn rate windows', + })} +
(); - const [recalledMessages, setRecalledMessages] = useState(undefined); - const [loading, setLoading] = useState(false); const [subscription, setSubscription] = useState(); const [conversationId, setConversationId] = useState(); - const { conversation, displayedMessages, setDisplayedMessages, save, saveTitle } = - useConversation({ - conversationId, - connectorId, - chatService, - }); + const { + conversation, + displayedMessages, + setDisplayedMessages, + getSystemMessage, + save, + saveTitle, + } = useConversation({ + conversationId, + connectorId, + chatService, + initialMessages, + }); const conversationTitle = conversationId ? conversation.value?.conversation.title || '' @@ -62,21 +67,16 @@ function ChatContent({ const controllerRef = useRef(new AbortController()); - const reloadRecalledMessages = useCallback(async () => { - setLoading(true); - - setDisplayedMessages(initialMessages); - - setRecalledMessages(undefined); + const reloadRecalledMessages = useCallback( + async (messages: Message[]) => { + controllerRef.current.abort(); - controllerRef.current.abort(); + const controller = (controllerRef.current = new AbortController()); - const controller = (controllerRef.current = new AbortController()); + const isStartOfConversation = + messages.some((message) => message.message.role === MessageRole.Assistant) === false; - let appendedMessages: Message[] = []; - - if (chatService.hasFunction('recall')) { - try { + if (isStartOfConversation && chatService.hasFunction('recall')) { // manually execute recall function and append to list of // messages const functionCall = { @@ -86,7 +86,7 @@ function ChatContent({ const response = await chatService.executeFunction({ ...functionCall, - messages: initialMessages, + messages, signal: controller.signal, connectorId, }); @@ -95,7 +95,7 @@ function ChatContent({ throw new Error('Recall function unexpectedly returned an Observable'); } - appendedMessages = [ + return [ { '@timestamp': new Date().toISOString(), message: { @@ -117,43 +117,60 @@ function ChatContent({ }, }, ]; - - setRecalledMessages(appendedMessages); - } catch (err) { - // eslint-disable-next-line no-console - console.error(err); - setRecalledMessages([]); } - } - }, [chatService, connectorId, initialMessages, setDisplayedMessages]); - useEffect(() => { - let lastPendingMessage: PendingMessage | undefined; + return []; + }, + [chatService, connectorId] + ); + + const reloadConversation = useCallback(async () => { + setLoading(true); + + setDisplayedMessages(initialMessages); + setPendingMessage(undefined); + + const messages = [getSystemMessage(), ...initialMessages]; - if (recalledMessages === undefined) { - // don't do anything, it's loading - return; - } + const recalledMessages = await reloadRecalledMessages(messages); + const next = messages.concat(recalledMessages); + + setDisplayedMessages(next); + + let lastPendingMessage: PendingMessage | undefined; const nextSubscription = chatService - .chat({ messages: displayedMessages.concat(recalledMessages), connectorId, function: 'none' }) + .chat({ messages: next, connectorId, function: 'none' }) .subscribe({ next: (msg) => { lastPendingMessage = msg; setPendingMessage(() => msg); }, complete: () => { + setDisplayedMessages((prev) => + prev.concat({ + '@timestamp': new Date().toISOString(), + ...lastPendingMessage!, + }) + ); setPendingMessage(lastPendingMessage); setLoading(false); }, }); setSubscription(nextSubscription); - }, [chatService, connectorId, displayedMessages, setDisplayedMessages, recalledMessages]); + }, [ + reloadRecalledMessages, + chatService, + connectorId, + initialMessages, + getSystemMessage, + setDisplayedMessages, + ]); useEffect(() => { - reloadRecalledMessages(); - }, [reloadRecalledMessages]); + reloadConversation(); + }, [reloadConversation]); useEffect(() => { setDisplayedMessages(initialMessages); @@ -163,17 +180,22 @@ function ChatContent({ const messagesWithPending = useMemo(() => { return pendingMessage - ? displayedMessages.concat(recalledMessages || []).concat({ + ? displayedMessages.concat({ '@timestamp': new Date().toISOString(), message: { ...pendingMessage.message, }, }) - : displayedMessages.concat(recalledMessages || []); - }, [pendingMessage, displayedMessages, recalledMessages]); - - const lastAssistantMessage = last( - messagesWithPending.filter((message) => message.message.role === MessageRole.Assistant) + : displayedMessages; + }, [pendingMessage, displayedMessages]); + + const firstAssistantMessage = first( + messagesWithPending.filter( + (message) => + message.message.role === MessageRole.Assistant && + (!message.message.function_call?.trigger || + message.message.function_call.trigger === MessageRole.Assistant) + ) ); return ( @@ -181,7 +203,7 @@ function ChatContent({ {}} /> @@ -216,7 +238,7 @@ function ChatContent({ { - reloadRecalledMessages(); + reloadConversation(); }} /> @@ -237,7 +259,7 @@ function ChatContent({ onClose={() => { setIsOpen(() => false); }} - messages={messagesWithPending} + messages={displayedMessages} conversationId={conversationId} startedFrom="contextualInsight" onChatComplete={(nextMessages) => { diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.ts index 965a8b899879ad..6970c53e28bf19 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_conversation.ts @@ -6,7 +6,7 @@ */ import { i18n } from '@kbn/i18n'; import { merge, omit } from 'lodash'; -import { Dispatch, SetStateAction, useMemo, useState } from 'react'; +import { Dispatch, SetStateAction, useCallback, useMemo, useState } from 'react'; import { type Conversation, type Message } from '../../common'; import { ConversationCreateRequest, MessageRole } from '../../common/types'; import { getAssistantSetupMessage } from '../service/get_assistant_setup_message'; @@ -20,14 +20,17 @@ export function useConversation({ conversationId, chatService, connectorId, + initialMessages = [], }: { conversationId?: string; chatService?: ObservabilityAIAssistantChatService; // will eventually resolve to a non-nullish value connectorId: string | undefined; + initialMessages?: Message[]; }): { conversation: AbortableAsyncState; displayedMessages: Message[]; setDisplayedMessages: Dispatch>; + getSystemMessage: () => Message; save: (messages: Message[], handleRefreshConversations?: () => void) => Promise; saveTitle: ( title: string, @@ -40,20 +43,25 @@ export function useConversation({ services: { notifications }, } = useKibana(); - const [displayedMessages, setDisplayedMessages] = useState([]); + const [displayedMessages, setDisplayedMessages] = useState(initialMessages); + + const getSystemMessage = useCallback(() => { + return getAssistantSetupMessage({ contexts: chatService?.getContexts() || [] }); + }, [chatService]); const displayedMessagesWithHardcodedSystemMessage = useMemo(() => { if (!chatService) { return displayedMessages; } - const systemMessage = getAssistantSetupMessage({ contexts: chatService?.getContexts() || [] }); + + const systemMessage = getSystemMessage(); if (displayedMessages[0]?.message.role === MessageRole.User) { return [systemMessage, ...displayedMessages]; } return [systemMessage, ...displayedMessages.slice(1)]; - }, [displayedMessages, chatService]); + }, [displayedMessages, chatService, getSystemMessage]); const conversation: AbortableAsyncState = useAbortableAsync( @@ -87,6 +95,7 @@ export function useConversation({ conversation, displayedMessages: displayedMessagesWithHardcodedSystemMessage, setDisplayedMessages, + getSystemMessage, save: (messages: Message[], handleRefreshConversations?: () => void) => { const conversationObject = conversation.value!; @@ -106,7 +115,13 @@ export function useConversation({ id: conversationId, }, }, - omit(conversationObject, 'conversation.last_updated', 'namespace', 'user'), + omit( + conversationObject, + 'conversation.last_updated', + 'namespace', + 'user', + 'messages' + ), { messages } ), }, diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts index 8d8afe6fb9cca9..6ad1d0746a517e 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.test.ts @@ -81,6 +81,12 @@ describe('useTimeline', () => { hookResult = renderHook((props) => useTimeline(props), { initialProps: { messages: [ + { + message: { + role: MessageRole.System, + content: 'You are a helpful assistant for Elastic Observability', + }, + }, { message: { role: MessageRole.User, @@ -122,6 +128,7 @@ describe('useTimeline', () => { chatService: { chat: () => {}, hasRenderFunction: () => {}, + hasFunction: () => {}, }, } as unknown as HookProps, }); @@ -308,35 +315,71 @@ describe('useTimeline', () => { canGiveFeedback: false, }, }); + }); - act(() => { - subject.next({ message: { role: MessageRole.Assistant, content: 'Goodbye' } }); + describe('and it pushes the next part', () => { + beforeEach(() => { + act(() => { + subject.next({ message: { role: MessageRole.Assistant, content: 'Goodbye' } }); + }); }); - expect(hookResult.result.current.items[2]).toMatchObject({ - role: MessageRole.Assistant, - content: 'Goodbye', - loading: true, - actions: { - canRegenerate: false, - canGiveFeedback: false, - }, + it('adds the partial response', () => { + expect(hookResult.result.current.items[2]).toMatchObject({ + role: MessageRole.Assistant, + content: 'Goodbye', + loading: true, + actions: { + canRegenerate: false, + canGiveFeedback: false, + }, + }); }); - act(() => { - subject.complete(); - }); + describe('and it completes', () => { + beforeEach(async () => { + act(() => { + subject.complete(); + }); - await hookResult.waitForNextUpdate(WAIT_OPTIONS); + await hookResult.waitForNextUpdate(WAIT_OPTIONS); + }); - expect(hookResult.result.current.items[2]).toMatchObject({ - role: MessageRole.Assistant, - content: 'Goodbye', - loading: false, - actions: { - canRegenerate: true, - canGiveFeedback: false, - }, + it('adds the completed message', () => { + expect(hookResult.result.current.items[2]).toMatchObject({ + role: MessageRole.Assistant, + content: 'Goodbye', + loading: false, + actions: { + canRegenerate: true, + canGiveFeedback: false, + }, + }); + }); + + describe('and the user edits a message', () => { + beforeEach(() => { + act(() => { + hookResult.result.current.onEdit( + hookResult.result.current.items[1] as ChatTimelineItem, + { + '@timestamp': new Date().toISOString(), + message: { content: 'Edited message', role: MessageRole.User }, + } + ); + subject.next({ message: { role: MessageRole.Assistant, content: '' } }); + subject.complete(); + }); + }); + + it('calls onChatUpdate with the edited message', () => { + expect(hookResult.result.current.items.length).toEqual(4); + expect((hookResult.result.current.items[2] as ChatTimelineItem).content).toEqual( + 'Edited message' + ); + expect((hookResult.result.current.items[3] as ChatTimelineItem).content).toEqual(''); + }); + }); }); }); @@ -379,7 +422,7 @@ describe('useTimeline', () => { }); }); - describe('and it being regenerated', () => { + describe('and it is being regenerated', () => { beforeEach(() => { act(() => { hookResult.result.current.onRegenerate( @@ -390,6 +433,8 @@ describe('useTimeline', () => { }); it('updates the last item in the array to be loading', () => { + expect(hookResult.result.current.items.length).toEqual(3); + expect(hookResult.result.current.items[2]).toEqual({ display: { hide: false, diff --git a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts index 7db568a07a99e2..64d82cabb94370 100644 --- a/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts +++ b/x-pack/plugins/observability_ai_assistant/public/hooks/use_timeline.ts @@ -8,7 +8,7 @@ import { i18n } from '@kbn/i18n'; import { AbortError } from '@kbn/kibana-utils-plugin/common'; import type { AuthenticatedUser } from '@kbn/security-plugin/common'; -import { last } from 'lodash'; +import { flatten, last } from 'lodash'; import { useEffect, useMemo, useRef, useState } from 'react'; import usePrevious from 'react-use/lib/usePrevious'; import { isObservable, Observable, Subscription } from 'rxjs'; @@ -333,15 +333,16 @@ export function useTimeline({ return { items, onEdit: async (item, newMessage) => { - const indexOf = items.indexOf(item); - const sliced = messages.slice(0, indexOf - 1); + const indexOf = flatten(items).indexOf(item); + const sliced = messages.slice(0, indexOf); const nextMessages = await chat(sliced.concat(newMessage)); onChatComplete(nextMessages); }, onFeedback: (item, feedback) => {}, onRegenerate: (item) => { - const indexOf = items.indexOf(item); - chat(messages.slice(0, indexOf - 1)).then((nextMessages) => onChatComplete(nextMessages)); + const indexOf = flatten(items).indexOf(item); + + chat(messages.slice(0, indexOf)).then((nextMessages) => onChatComplete(nextMessages)); }, onStopGenerating: () => { subscription?.unsubscribe(); diff --git a/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts b/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts index f0df01d87168d5..2332f63a54c78e 100644 --- a/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts +++ b/x-pack/plugins/observability_ai_assistant/server/service/client/index.ts @@ -100,7 +100,7 @@ export class ObservabilityAIAssistantClient { await this.dependencies.esClient.delete({ id: conversation._id, index: conversation._index, - refresh: 'wait_for', + refresh: true, }); }; @@ -244,7 +244,7 @@ export class ObservabilityAIAssistantClient { id: document._id, index: document._index, doc: updatedConversation, - refresh: 'wait_for', + refresh: true, }); return updatedConversation; @@ -334,7 +334,7 @@ export class ObservabilityAIAssistantClient { id: document._id, index: document._index, doc: { conversation: { title } }, - refresh: 'wait_for', + refresh: true, }); return updatedConversation; @@ -356,7 +356,7 @@ export class ObservabilityAIAssistantClient { await this.dependencies.esClient.index({ index: this.dependencies.resources.aliases.conversations, document: createdConversation, - refresh: 'wait_for', + refresh: true, }); return createdConversation; diff --git a/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts b/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts index d70879bf46d3e4..be10c3eaaa5d58 100644 --- a/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts +++ b/x-pack/plugins/observability_ai_assistant/server/service/kb_service/index.ts @@ -218,7 +218,7 @@ export class KnowledgeBaseService { >({ index: this.dependencies.resources.aliases.kb, query, - size: 10, + size: 5, _source: { includes: ['text', 'is_correction', 'labels'], }, diff --git a/x-pack/plugins/profiling/e2e/cypress/e2e/empty_state/home.cy.ts b/x-pack/plugins/profiling/e2e/cypress/e2e/empty_state/home.cy.ts index bba7a3c014c41d..1a839499176907 100644 --- a/x-pack/plugins/profiling/e2e/cypress/e2e/empty_state/home.cy.ts +++ b/x-pack/plugins/profiling/e2e/cypress/e2e/empty_state/home.cy.ts @@ -83,4 +83,32 @@ describe('Home page with empty state', () => { cy.contains('Delete existing profiling data'); }); }); + + it('shows disabled button for users without privileges', () => { + cy.intercept('GET', '/internal/profiling/setup/es_resources', { + body: { + has_setup: false, + has_data: false, + pre_8_9_1_data: false, + has_required_role: false, + }, + }).as('getEsResources'); + cy.visitKibana('/app/profiling'); + cy.wait('@getEsResources'); + cy.contains('Set up Universal Profiling').should('be.disabled'); + }); + + it('shows emabled button for users without privileges', () => { + cy.intercept('GET', '/internal/profiling/setup/es_resources', { + body: { + has_setup: false, + has_data: false, + pre_8_9_1_data: false, + has_required_role: true, + }, + }).as('getEsResources'); + cy.visitKibana('/app/profiling'); + cy.wait('@getEsResources'); + cy.contains('Set up Universal Profiling').should('not.be.disabled'); + }); }); diff --git a/x-pack/plugins/profiling/kibana.jsonc b/x-pack/plugins/profiling/kibana.jsonc index aa1ae58a2b1902..104196bababc99 100644 --- a/x-pack/plugins/profiling/kibana.jsonc +++ b/x-pack/plugins/profiling/kibana.jsonc @@ -10,6 +10,7 @@ "optionalPlugins": [ "spaces", "usageCollection", + "security", "cloud", "fleet" ], diff --git a/x-pack/plugins/profiling/public/components/check_setup.tsx b/x-pack/plugins/profiling/public/components/check_setup.tsx index 3bfb920f25eb14..72d2985cb90e65 100644 --- a/x-pack/plugins/profiling/public/components/check_setup.tsx +++ b/x-pack/plugins/profiling/public/components/check_setup.tsx @@ -13,6 +13,7 @@ import { EuiLink, EuiLoadingSpinner, EuiText, + EuiToolTip, } from '@elastic/eui'; import { i18n } from '@kbn/i18n'; import { FormattedMessage } from '@kbn/i18n-react'; @@ -91,6 +92,7 @@ export function CheckSetup({ children }: { children: React.ReactElement }) { !!error; if (displaySetupScreen) { + const isButtonDisabled = postSetupLoading || data?.has_required_role === false; return ( { - event.preventDefault(); - - setPostSetupLoading(true); - - postSetupResources({ http }) - .then(() => refresh()) - .catch((err) => { - const message = err?.body?.message ?? err.message ?? String(err); - - notifications.toasts.addError(err, { - title: i18n.translate( - 'xpack.profiling.checkSetup.setupFailureToastTitle', - { - defaultMessage: 'Failed to complete setup', - } - ), - toastMessage: message, - }); - }) - .finally(() => { - setPostSetupLoading(false); - }); - }} - fill - isLoading={postSetupLoading} + - {!postSetupLoading - ? i18n.translate('xpack.profiling.noDataConfig.action.buttonLabel', { - defaultMessage: 'Set up Universal Profiling', - }) - : i18n.translate('xpack.profiling.noDataConfig.action.buttonLoadingLabel', { - defaultMessage: 'Setting up Universal Profiling...', - })} - + { + event.preventDefault(); + + setPostSetupLoading(true); + + postSetupResources({ http }) + .then(() => refresh()) + .catch((err) => { + const message = err?.body?.message ?? err.message ?? String(err); + + notifications.toasts.addError(err, { + title: i18n.translate( + 'xpack.profiling.checkSetup.setupFailureToastTitle', + { + defaultMessage: 'Failed to complete setup', + } + ), + toastMessage: message, + }); + }) + .finally(() => { + setPostSetupLoading(false); + }); + }} + fill + isLoading={postSetupLoading} + > + {!postSetupLoading + ? i18n.translate('xpack.profiling.noDataConfig.action.buttonLabel', { + defaultMessage: 'Set up Universal Profiling', + }) + : i18n.translate('xpack.profiling.noDataConfig.action.buttonLoadingLabel', { + defaultMessage: 'Setting up Universal Profiling...', + })} + + ), }, }, diff --git a/x-pack/plugins/profiling/public/services.ts b/x-pack/plugins/profiling/public/services.ts index 750e9eab65a96f..7f16747f596c2a 100644 --- a/x-pack/plugins/profiling/public/services.ts +++ b/x-pack/plugins/profiling/public/services.ts @@ -26,6 +26,7 @@ export interface ProfilingSetupStatus { has_setup: boolean; has_data: boolean; pre_8_9_1_data: boolean; + has_required_role: boolean; unauthorized?: boolean; } diff --git a/x-pack/plugins/profiling/server/lib/setup/get_has_setup_privileges.ts b/x-pack/plugins/profiling/server/lib/setup/get_has_setup_privileges.ts new file mode 100644 index 00000000000000..83bd21b1740b80 --- /dev/null +++ b/x-pack/plugins/profiling/server/lib/setup/get_has_setup_privileges.ts @@ -0,0 +1,39 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { KibanaRequest } from '@kbn/core/server'; +import { INTEGRATIONS_PLUGIN_ID, PLUGIN_ID as FLEET_PLUGIN_ID } from '@kbn/fleet-plugin/common'; +import { ProfilingPluginStartDeps } from '../../types'; + +export async function getHasSetupPrivileges({ + securityPluginStart, + request, +}: { + securityPluginStart: NonNullable; + request: KibanaRequest; +}) { + // If we have a license which doesn't enable security, or we're a legacy user we shouldn't disable any ui capabilities + if (!securityPluginStart.authz.mode.useRbacForRequest(request)) { + return true; + } + + const { hasAllRequested } = await securityPluginStart.authz + .checkPrivilegesWithRequest(request) + .globally({ + elasticsearch: { + cluster: ['manage', 'monitor'], + index: { + 'profiling-*': ['read'], + }, + }, + kibana: [ + securityPluginStart.authz.actions.api.get(`${FLEET_PLUGIN_ID}-all`), + securityPluginStart.authz.actions.api.get(`${INTEGRATIONS_PLUGIN_ID}-all`), + ], + }); + return hasAllRequested; +} diff --git a/x-pack/plugins/profiling/server/lib/setup/security_role.ts b/x-pack/plugins/profiling/server/lib/setup/security_role.ts deleted file mode 100644 index b48a1d9f63a287..00000000000000 --- a/x-pack/plugins/profiling/server/lib/setup/security_role.ts +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { - METADATA_VERSION, - PROFILING_READER_ROLE_NAME, -} from '@kbn/profiling-data-access-plugin/common'; -import { ProfilingSetupOptions } from '@kbn/profiling-data-access-plugin/common/setup'; - -export async function setSecurityRole({ client }: ProfilingSetupOptions) { - const esClient = client.getEsClient(); - await esClient.security.putRole({ - name: PROFILING_READER_ROLE_NAME, - indices: [ - { - names: ['profiling-*', '.profiling-*'], - privileges: ['read', 'view_index_metadata'], - }, - ], - cluster: ['monitor'], - metadata: { - version: METADATA_VERSION, - }, - }); -} diff --git a/x-pack/plugins/profiling/server/routes/setup/route.ts b/x-pack/plugins/profiling/server/routes/setup/route.ts index 5ee297ee68791b..cbd0f6ee2170ce 100644 --- a/x-pack/plugins/profiling/server/routes/setup/route.ts +++ b/x-pack/plugins/profiling/server/routes/setup/route.ts @@ -5,16 +5,17 @@ * 2.0. */ -import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; import { ProfilingSetupOptions } from '@kbn/profiling-data-access-plugin/common/setup'; +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; import { RouteRegisterParameters } from '..'; import { getRoutePaths } from '../../../common'; -import { getCloudSetupInstructions } from './get_cloud_setup_instructions'; +import { getHasSetupPrivileges } from '../../lib/setup/get_has_setup_privileges'; import { handleRouteHandlerError } from '../../utils/handle_route_error_handler'; import { getClient } from '../compat'; +import { getCloudSetupInstructions } from './get_cloud_setup_instructions'; +import { getSelfManagedInstructions } from './get_self_managed_instructions'; import { setupCloud } from './setup_cloud'; import { setupSelfManaged } from './setup_self_managed'; -import { getSelfManagedInstructions } from './get_self_managed_instructions'; export function registerSetupRoute({ router, @@ -23,7 +24,6 @@ export function registerSetupRoute({ dependencies, }: RouteRegisterParameters) { const paths = getRoutePaths(); - // Check if Elasticsearch and Fleet are set up for Universal Profiling router.get( { path: paths.HasSetupESResources, @@ -32,16 +32,22 @@ export function registerSetupRoute({ }, async (context, request, response) => { try { - const esClient = await getClient(context); + const hasRequiredRole = dependencies.start.security + ? await getHasSetupPrivileges({ + securityPluginStart: dependencies.start.security, + request, + }) + : true; + const core = await context.core; const profilingStatus = await dependencies.start.profilingDataAccess.services.getStatus({ - esClient, + esClient: core.elasticsearch.client, soClient: core.savedObjects.client, spaceId: dependencies.setup.spaces?.spacesService?.getSpaceId(request), }); - return response.ok({ body: profilingStatus }); + return response.ok({ body: { ...profilingStatus, has_required_role: hasRequiredRole } }); } catch (error) { return handleRouteHandlerError({ error, @@ -83,9 +89,10 @@ export function registerSetupRoute({ dependencies.setup.spaces?.spacesService?.getSpaceId(request) ?? DEFAULT_SPACE_ID, }; + const scopedESClient = (await context.core).elasticsearch.client; const { type, setupState } = await dependencies.start.profilingDataAccess.services.getSetupState({ - esClient, + esClient: scopedESClient, soClient: core.savedObjects.client, spaceId: dependencies.setup.spaces?.spacesService?.getSpaceId(request) ?? DEFAULT_SPACE_ID, diff --git a/x-pack/plugins/profiling/server/routes/setup/setup_cloud.ts b/x-pack/plugins/profiling/server/routes/setup/setup_cloud.ts index c4978710991ceb..5e282e21e4c765 100644 --- a/x-pack/plugins/profiling/server/routes/setup/setup_cloud.ts +++ b/x-pack/plugins/profiling/server/routes/setup/setup_cloud.ts @@ -12,7 +12,6 @@ import { createSymbolizerPackagePolicy, removeProfilingFromApmPackagePolicy, } from '../../lib/setup/fleet_policies'; -import { setSecurityRole } from '../../lib/setup/security_role'; import { ProfilingCloudSetupOptions } from '../../lib/setup/types'; export async function setupCloud({ @@ -24,7 +23,6 @@ export async function setupCloud({ }) { const executeAdminFunctions = [ ...(setupState.resource_management.enabled ? [] : [enableResourceManagement]), - ...(setupState.permissions.configured ? [] : [setSecurityRole]), ...(setupState.settings.configured ? [] : [setMaximumBuckets]), ]; diff --git a/x-pack/plugins/profiling/server/routes/setup/setup_self_managed.ts b/x-pack/plugins/profiling/server/routes/setup/setup_self_managed.ts index c82721780cd0cd..4f15624f4c6af2 100644 --- a/x-pack/plugins/profiling/server/routes/setup/setup_self_managed.ts +++ b/x-pack/plugins/profiling/server/routes/setup/setup_self_managed.ts @@ -7,7 +7,6 @@ import { ProfilingSetupOptions, SetupState } from '@kbn/profiling-data-access-plugin/common/setup'; import { enableResourceManagement, setMaximumBuckets } from '../../lib/setup/cluster_settings'; -import { setSecurityRole } from '../../lib/setup/security_role'; export async function setupSelfManaged({ setupState, @@ -18,7 +17,6 @@ export async function setupSelfManaged({ }) { const executeFunctions = [ ...(setupState.resource_management.enabled ? [] : [enableResourceManagement]), - ...(setupState.permissions.configured ? [] : [setSecurityRole]), ...(setupState.settings.configured ? [] : [setMaximumBuckets]), ]; diff --git a/x-pack/plugins/profiling/server/types.ts b/x-pack/plugins/profiling/server/types.ts index 24705921bbbf9c..adc672c932083d 100644 --- a/x-pack/plugins/profiling/server/types.ts +++ b/x-pack/plugins/profiling/server/types.ts @@ -16,6 +16,7 @@ import { ProfilingDataAccessPluginSetup, ProfilingDataAccessPluginStart, } from '@kbn/profiling-data-access-plugin/server'; +import { SecurityPluginSetup, SecurityPluginStart } from '@kbn/security-plugin/server'; export interface ProfilingPluginSetupDeps { observability: ObservabilityPluginSetup; @@ -25,6 +26,7 @@ export interface ProfilingPluginSetupDeps { spaces?: SpacesPluginSetup; usageCollection?: UsageCollectionSetup; profilingDataAccess: ProfilingDataAccessPluginSetup; + security?: SecurityPluginSetup; } export interface ProfilingPluginStartDeps { @@ -34,6 +36,7 @@ export interface ProfilingPluginStartDeps { fleet?: FleetStartContract; spaces?: SpacesPluginStart; profilingDataAccess: ProfilingDataAccessPluginStart; + security?: SecurityPluginStart; } // eslint-disable-next-line @typescript-eslint/no-empty-interface diff --git a/x-pack/plugins/profiling/tsconfig.json b/x-pack/plugins/profiling/tsconfig.json index af7971b5115d54..7705c70d0d1b46 100644 --- a/x-pack/plugins/profiling/tsconfig.json +++ b/x-pack/plugins/profiling/tsconfig.json @@ -50,7 +50,8 @@ "@kbn/profiling-data-access-plugin", "@kbn/embeddable-plugin", "@kbn/profiling-utils", - "@kbn/advanced-settings-plugin" + "@kbn/advanced-settings-plugin", + "@kbn/security-plugin" // add references to other TypeScript projects the plugin depends on // requiredPlugins from ./kibana.json diff --git a/x-pack/plugins/profiling_data_access/common/cloud_setup.test.ts b/x-pack/plugins/profiling_data_access/common/cloud_setup.test.ts index 1d99c6346c4c60..3071177cab26e2 100644 --- a/x-pack/plugins/profiling_data_access/common/cloud_setup.test.ts +++ b/x-pack/plugins/profiling_data_access/common/cloud_setup.test.ts @@ -14,9 +14,6 @@ import { mergePartialSetupStates } from './setup'; const createCloudState = (available: boolean): PartialCloudSetupState => ({ cloud: { available } }); const createDataState = (available: boolean): PartialCloudSetupState => ({ data: { available } }); -const createPermissionState = (configured: boolean): PartialCloudSetupState => ({ - permissions: { configured }, -}); const createCollectorPolicyState = (installed: boolean): PartialCloudSetupState => ({ policies: { collector: { installed } }, }); @@ -75,18 +72,6 @@ describe('Merging partial state operations', () => { expect(mergedState.policies.collector.installed).toEqual(true); expect(mergedState.policies.symbolizer.installed).toEqual(true); }); - it('returns false when permission is not configured', () => { - const mergedState = mergePartialSetupStates(defaultSetupState, [ - createCollectorPolicyState(true), - createSymbolizerPolicyState(true), - createProfilingInApmPolicyState(true), - createResourceState({ enabled: true, created: true }), - createSettingsState(true), - createPermissionState(false), - ]); - - expect(areCloudResourcesSetup(mergedState)).toBeFalsy(); - }); it('returns false when resource management is not enabled', () => { const mergedState = mergePartialSetupStates(defaultSetupState, [ @@ -95,7 +80,6 @@ describe('Merging partial state operations', () => { createProfilingInApmPolicyState(true), createResourceState({ enabled: false, created: true }), createSettingsState(true), - createPermissionState(true), ]); expect(areCloudResourcesSetup(mergedState)).toBeFalsy(); @@ -108,7 +92,6 @@ describe('Merging partial state operations', () => { createProfilingInApmPolicyState(true), createResourceState({ enabled: true, created: false }), createSettingsState(true), - createPermissionState(true), ]); expect(areCloudResourcesSetup(mergedState)).toBeFalsy(); @@ -121,7 +104,6 @@ describe('Merging partial state operations', () => { createProfilingInApmPolicyState(true), createResourceState({ enabled: true, created: true }), createSettingsState(false), - createPermissionState(true), ]); expect(areCloudResourcesSetup(mergedState)).toBeFalsy(); @@ -134,7 +116,6 @@ describe('Merging partial state operations', () => { createProfilingInApmPolicyState(false), createResourceState({ enabled: true, created: true }), createSettingsState(true), - createPermissionState(true), ]); expect(areCloudResourcesSetup(mergedState)).toBeTruthy(); @@ -147,7 +128,6 @@ describe('Merging partial state operations', () => { createProfilingInApmPolicyState(false), createResourceState({ enabled: true, created: true }), createSettingsState(true), - createPermissionState(true), ]); expect(areCloudResourcesSetup(mergedState)).toBeFalsy(); @@ -160,7 +140,6 @@ describe('Merging partial state operations', () => { createProfilingInApmPolicyState(false), createResourceState({ enabled: true, created: true }), createSettingsState(true), - createPermissionState(true), ]); expect(areCloudResourcesSetup(mergedState)).toBeFalsy(); @@ -173,7 +152,6 @@ describe('Merging partial state operations', () => { createProfilingInApmPolicyState(true), createResourceState({ enabled: true, created: true }), createSettingsState(true), - createPermissionState(true), ]); expect(areCloudResourcesSetup(mergedState)).toBeFalsy(); diff --git a/x-pack/plugins/profiling_data_access/common/index.ts b/x-pack/plugins/profiling_data_access/common/index.ts index 8482620dcb4748..07ea07f4ca1110 100644 --- a/x-pack/plugins/profiling_data_access/common/index.ts +++ b/x-pack/plugins/profiling_data_access/common/index.ts @@ -7,7 +7,6 @@ export { getApmPolicy, ELASTIC_CLOUD_APM_POLICY } from './get_apm_policy'; export { MAX_BUCKETS } from './cluster_settings'; -export { METADATA_VERSION, PROFILING_READER_ROLE_NAME } from './security_role'; export { getCollectorPolicy, getSymbolizerPolicy, diff --git a/x-pack/plugins/profiling_data_access/common/security_role.ts b/x-pack/plugins/profiling_data_access/common/security_role.ts deleted file mode 100644 index ed6cf1dbd4e62c..00000000000000 --- a/x-pack/plugins/profiling_data_access/common/security_role.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { PartialSetupState, ProfilingSetupOptions } from './setup'; - -export const PROFILING_READER_ROLE_NAME = 'profiling-reader'; -export const METADATA_VERSION = 1; - -export async function validateSecurityRole({ - client, -}: ProfilingSetupOptions): Promise { - const esClient = client.getEsClient(); - const roles = await esClient.security.getRole(); - const profilingRole = roles[PROFILING_READER_ROLE_NAME]; - return { - permissions: { - configured: !!profilingRole && profilingRole.metadata.version === METADATA_VERSION, - }, - }; -} diff --git a/x-pack/plugins/profiling_data_access/common/setup.test.ts b/x-pack/plugins/profiling_data_access/common/setup.test.ts index 01826ac7fa913c..5b63b64732da87 100644 --- a/x-pack/plugins/profiling_data_access/common/setup.test.ts +++ b/x-pack/plugins/profiling_data_access/common/setup.test.ts @@ -13,9 +13,6 @@ import { } from './setup'; const createDataState = (available: boolean): PartialSetupState => ({ data: { available } }); -const createPermissionState = (configured: boolean): PartialSetupState => ({ - permissions: { configured }, -}); function createResourceState({ enabled, @@ -49,7 +46,6 @@ describe('Merging partial state operations', () => { const mergedState = mergePartialSetupStates(defaultSetupState, [createDataState(true)]); expect(mergedState.data.available).toEqual(true); expect(mergedState.settings.configured).toEqual(false); - expect(mergedState.permissions.configured).toEqual(false); expect(mergedState.resources.created).toEqual(false); }); @@ -62,21 +58,10 @@ describe('Merging partial state operations', () => { expect(mergedState.resources.created).toEqual(true); }); - it('returns false when permission is not configured', () => { - const mergedState = mergePartialSetupStates(defaultSetupState, [ - createResourceState({ enabled: true, created: true }), - createSettingsState(true), - createPermissionState(false), - ]); - - expect(areResourcesSetup(mergedState)).toBeFalsy(); - }); - it('returns false when resource management is not enabled', () => { const mergedState = mergePartialSetupStates(defaultSetupState, [ createResourceState({ enabled: false, created: true }), createSettingsState(true), - createPermissionState(true), ]); expect(areResourcesSetup(mergedState)).toBeFalsy(); @@ -86,7 +71,6 @@ describe('Merging partial state operations', () => { const mergedState = mergePartialSetupStates(defaultSetupState, [ createResourceState({ enabled: true, created: false }), createSettingsState(true), - createPermissionState(true), ]); expect(areResourcesSetup(mergedState)).toBeFalsy(); @@ -96,7 +80,6 @@ describe('Merging partial state operations', () => { const mergedState = mergePartialSetupStates(defaultSetupState, [ createResourceState({ enabled: true, created: true }), createSettingsState(false), - createPermissionState(true), ]); expect(areResourcesSetup(mergedState)).toBeFalsy(); @@ -106,7 +89,6 @@ describe('Merging partial state operations', () => { const mergedState = mergePartialSetupStates(defaultSetupState, [ createResourceState({ enabled: true, created: true }), createSettingsState(true), - createPermissionState(true), ]); expect(areResourcesSetup(mergedState)).toBeTruthy(); diff --git a/x-pack/plugins/profiling_data_access/common/setup.ts b/x-pack/plugins/profiling_data_access/common/setup.ts index 934c425ed0af90..625423f48ab201 100644 --- a/x-pack/plugins/profiling_data_access/common/setup.ts +++ b/x-pack/plugins/profiling_data_access/common/setup.ts @@ -26,9 +26,6 @@ export interface SetupState { data: { available: boolean; }; - permissions: { - configured: boolean; - }; resource_management: { enabled: boolean; }; @@ -48,9 +45,6 @@ export function createDefaultSetupState(): SetupState { data: { available: false, }, - permissions: { - configured: false, - }, resource_management: { enabled: false, }, @@ -65,12 +59,7 @@ export function createDefaultSetupState(): SetupState { } export function areResourcesSetup(state: SetupState): boolean { - return ( - state.resource_management.enabled && - state.resources.created && - state.permissions.configured && - state.settings.configured - ); + return state.resource_management.enabled && state.resources.created && state.settings.configured; } function mergeRecursivePartial(base: T, partial: RecursivePartial): T { diff --git a/x-pack/plugins/profiling_data_access/server/services/setup_state/cloud_setup_state.ts b/x-pack/plugins/profiling_data_access/server/services/setup_state/cloud_setup_state.ts index ed05677d21dfbd..3673e4191e3fc1 100644 --- a/x-pack/plugins/profiling_data_access/server/services/setup_state/cloud_setup_state.ts +++ b/x-pack/plugins/profiling_data_access/server/services/setup_state/cloud_setup_state.ts @@ -18,7 +18,6 @@ import { validateSymbolizerPackagePolicy, } from '../../../common/fleet_policies'; import { hasProfilingData } from '../../../common/has_profiling_data'; -import { validateSecurityRole } from '../../../common/security_role'; import { mergePartialSetupStates } from '../../../common/setup'; export async function cloudSetupState( @@ -30,7 +29,6 @@ export async function cloudSetupState( const verifyFunctions = [ validateMaximumBuckets, validateResourceManagement, - validateSecurityRole, validateCollectorPackagePolicy, validateSymbolizerPackagePolicy, validateProfilingInApmPackagePolicy, diff --git a/x-pack/plugins/profiling_data_access/server/services/setup_state/index.ts b/x-pack/plugins/profiling_data_access/server/services/setup_state/index.ts index 99d81ab7717933..d11668e1af6e9b 100644 --- a/x-pack/plugins/profiling_data_access/server/services/setup_state/index.ts +++ b/x-pack/plugins/profiling_data_access/server/services/setup_state/index.ts @@ -4,7 +4,7 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import { IScopedClusterClient, SavedObjectsClientContract } from '@kbn/core/server'; import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; import { CloudSetupStateType } from '../../../common/cloud_setup'; import { SetupStateType } from '../../../common/setup'; @@ -14,7 +14,7 @@ import { selfManagedSetupState } from './self_managed_setup_state'; export interface SetupStateParams { soClient: SavedObjectsClientContract; - esClient: ElasticsearchClient; + esClient: IScopedClusterClient; spaceId?: string; } @@ -26,12 +26,12 @@ export async function getSetupState({ soClient, spaceId, }: RegisterServicesParams & SetupStateParams): Promise { - const clientWithDefaultAuth = createProfilingEsClient({ - esClient, + const kibanaInternalProfilingESClient = createProfilingEsClient({ + esClient: esClient.asInternalUser, useDefaultAuth: true, }); - const clientWithProfilingAuth = createProfilingEsClient({ - esClient, + const profilingESClient = createProfilingEsClient({ + esClient: esClient.asCurrentUser, useDefaultAuth: false, }); @@ -42,8 +42,8 @@ export async function getSetupState({ } const setupState = await cloudSetupState({ - client: clientWithDefaultAuth, - clientWithProfilingAuth, + client: kibanaInternalProfilingESClient, + clientWithProfilingAuth: profilingESClient, logger, soClient, spaceId: spaceId ?? DEFAULT_SPACE_ID, @@ -58,8 +58,8 @@ export async function getSetupState({ } const setupState = await selfManagedSetupState({ - client: clientWithDefaultAuth, - clientWithProfilingAuth, + client: kibanaInternalProfilingESClient, + clientWithProfilingAuth: profilingESClient, logger, soClient, spaceId: spaceId ?? DEFAULT_SPACE_ID, diff --git a/x-pack/plugins/profiling_data_access/server/services/setup_state/self_managed_setup_state.ts b/x-pack/plugins/profiling_data_access/server/services/setup_state/self_managed_setup_state.ts index 062a75f0f1f027..ac7ff7ae7459e2 100644 --- a/x-pack/plugins/profiling_data_access/server/services/setup_state/self_managed_setup_state.ts +++ b/x-pack/plugins/profiling_data_access/server/services/setup_state/self_managed_setup_state.ts @@ -10,7 +10,6 @@ import { validateResourceManagement, } from '../../../common/cluster_settings'; import { hasProfilingData } from '../../../common/has_profiling_data'; -import { validateSecurityRole } from '../../../common/security_role'; import { createDefaultSetupState, mergePartialSetupStates, @@ -21,12 +20,7 @@ import { export async function selfManagedSetupState(params: ProfilingSetupOptions): Promise { const state = createDefaultSetupState(); - const verifyFunctions = [ - validateMaximumBuckets, - validateResourceManagement, - validateSecurityRole, - hasProfilingData, - ]; + const verifyFunctions = [validateMaximumBuckets, validateResourceManagement, hasProfilingData]; const partialStates = await Promise.all(verifyFunctions.map((fn) => fn(params))); diff --git a/x-pack/plugins/profiling_data_access/server/services/status/index.ts b/x-pack/plugins/profiling_data_access/server/services/status/index.ts index 0e32989ea88284..a2ad969847da7a 100644 --- a/x-pack/plugins/profiling_data_access/server/services/status/index.ts +++ b/x-pack/plugins/profiling_data_access/server/services/status/index.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { ElasticsearchClient, SavedObjectsClientContract } from '@kbn/core/server'; +import { IScopedClusterClient, SavedObjectsClientContract } from '@kbn/core/server'; import { ProfilingStatus } from '@kbn/profiling-utils'; import { areCloudResourcesSetup } from '../../../common/cloud_setup'; import { areResourcesSetup } from '../../../common/setup'; @@ -14,7 +14,7 @@ import { getSetupState } from '../setup_state'; export interface HasSetupParams { soClient: SavedObjectsClientContract; - esClient: ElasticsearchClient; + esClient: IScopedClusterClient; spaceId?: string; } diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/8.0.0/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/8.0.0/index.ts index 3dd5d8362a4973..3b7237ae8bb715 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/8.0.0/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/alerts/8.0.0/index.ts @@ -70,7 +70,8 @@ import type { ALERT_RULE_TIMESTAMP_OVERRIDE, } from '../../../../../field_maps/field_names'; // TODO: Create and import 8.0.0 versioned RuleAlertAction type -import type { RuleAlertAction, SearchTypes } from '../../../../../detection_engine/types'; +import type { SearchTypes } from '../../../../../detection_engine/types'; +import type { RuleAction } from '../../rule_schema'; /* DO NOT MODIFY THIS SCHEMA TO ADD NEW FIELDS. These types represent the alerts that shipped in 8.0.0. Any changes to these types should be bug fixes so the types more accurately represent the alerts from 8.0.0. @@ -110,7 +111,7 @@ export interface BaseFields800 { [ALERT_RISK_SCORE]: number; // TODO: version rule schemas and pull in 8.0.0 versioned rule schema to define alert rule parameters type [ALERT_RULE_PARAMETERS]: { [key: string]: SearchTypes }; - [ALERT_RULE_ACTIONS]: RuleAlertAction[]; + [ALERT_RULE_ACTIONS]: RuleAction[]; [ALERT_RULE_AUTHOR]: string[]; [ALERT_RULE_CREATED_AT]: string; [ALERT_RULE_CREATED_BY]: string; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.mock.ts index 06bfa3e9738209..22c507804e1d8a 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.mock.ts @@ -4,8 +4,9 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import type { ErrorSchema } from './error_schema'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import type { ErrorSchema } from './error_schema_legacy'; export const getErrorSchemaMock = ( id: string = '819eded6-e9c8-445b-a647-519aea39e063' diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.test.ts index 8326479db9c14c..164f5ee854efc3 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.test.ts @@ -8,7 +8,9 @@ import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; import { left } from 'fp-ts/lib/Either'; import { pipe } from 'fp-ts/lib/pipeable'; -import { ErrorSchema } from './error_schema'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { ErrorSchema } from './error_schema_legacy'; import { getErrorSchemaMock } from './error_schema.mock'; describe('error_schema', () => { diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema_legacy.ts similarity index 85% rename from x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema_legacy.ts index 53114d500bc219..c2efee05269c15 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/error_schema_legacy.ts @@ -8,7 +8,10 @@ import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; import * as t from 'io-ts'; -import { RuleSignatureId } from './rule_schema'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { RuleSignatureId } from './rule_schema_legacy'; + import { status_code, message } from './schemas'; // We use id: t.string intentionally and _never_ the id from global schemas as diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/index.ts index 00d17d55817a5a..0d243fc201fb96 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/index.ts @@ -8,8 +8,12 @@ export * from './alerts'; export * from './rule_response_actions'; export * from './rule_schema'; -export * from './error_schema'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +export * from './error_schema_legacy'; export * from './pagination'; export * from './schemas'; -export * from './sorting'; -export * from './warning_schema'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +export * from './sorting_legacy'; +export * from './warning_schema.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/endpoint.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/endpoint.ts deleted file mode 100644 index 0aa3f97509f80e..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/endpoint.ts +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { ENABLED_AUTOMATED_RESPONSE_ACTION_COMMANDS } from '../../../../endpoint/service/response_actions/constants'; - -// to enable using RESPONSE_ACTION_API_COMMANDS_NAMES as a type -function keyObject(arr: T): { [K in T[number]]: null } { - return Object.fromEntries(arr.map((v) => [v, null])) as never; -} - -export const EndpointParams = t.type({ - command: t.keyof(keyObject(ENABLED_AUTOMATED_RESPONSE_ACTION_COMMANDS)), - comment: t.union([t.string, t.undefined]), -}); - -export type EndpointParams = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/index.ts index 67385156998143..ccaf290dc5d338 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/index.ts @@ -5,6 +5,7 @@ * 2.0. */ -export * from './response_actions'; -export * from './endpoint'; -export * from './osquery'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +export { RESPONSE_ACTION_TYPES, SUPPORTED_RESPONSE_ACTION_TYPES } from './response_actions_legacy'; +export * from './response_actions.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/osquery.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/osquery.ts deleted file mode 100644 index 0fd840a0c8e719..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/osquery.ts +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { ecsMapping, arrayQueries } from '@kbn/osquery-io-ts-types'; - -export const OsqueryParams = t.type({ - query: t.union([t.string, t.undefined]), - ecs_mapping: t.union([ecsMapping, t.undefined]), - queries: t.union([arrayQueries, t.undefined]), - pack_id: t.union([t.string, t.undefined]), - saved_query_id: t.union([t.string, t.undefined]), -}); - -export const OsqueryParamsCamelCase = t.type({ - query: t.union([t.string, t.undefined]), - ecsMapping: t.union([ecsMapping, t.undefined]), - queries: t.union([arrayQueries, t.undefined]), - packId: t.union([t.string, t.undefined]), - savedQueryId: t.union([t.string, t.undefined]), -}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts new file mode 100644 index 00000000000000..10901049d476d3 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.gen.ts @@ -0,0 +1,109 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; +import { requiredOptional } from '@kbn/zod-helpers'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +export type ResponseActionTypes = z.infer; +export const ResponseActionTypes = z.enum(['.osquery', '.endpoint']); +export type ResponseActionTypesEnum = typeof ResponseActionTypes.enum; +export const ResponseActionTypesEnum = ResponseActionTypes.enum; + +export type EcsMapping = z.infer; +export const EcsMapping = z.object({}).catchall( + z.object({ + field: z.string().optional(), + value: z.union([z.string(), z.array(z.string())]).optional(), + }) +); + +export type OsqueryQuery = z.infer; +export const OsqueryQuery = z + .object({ + /** + * Query ID + */ + id: z.string(), + /** + * Query to execute + */ + query: z.string(), + ecs_mapping: EcsMapping.optional(), + /** + * Query version + */ + version: z.string().optional(), + platform: z.string().optional(), + removed: z.boolean().optional(), + snapshot: z.boolean().optional(), + }) + .transform(requiredOptional); + +export type OsqueryParams = z.infer; +export const OsqueryParams = z + .object({ + query: z.string().optional(), + ecs_mapping: EcsMapping.optional(), + queries: z.array(OsqueryQuery).optional(), + pack_id: z.string().optional(), + saved_query_id: z.string().optional(), + }) + .transform(requiredOptional); + +export type OsqueryParamsCamelCase = z.infer; +export const OsqueryParamsCamelCase = z + .object({ + query: z.string().optional(), + ecsMapping: EcsMapping.optional(), + queries: z.array(OsqueryQuery).optional(), + packId: z.string().optional(), + savedQueryId: z.string().optional(), + }) + .transform(requiredOptional); + +export type OsqueryResponseAction = z.infer; +export const OsqueryResponseAction = z.object({ + action_type_id: z.literal('.osquery'), + params: OsqueryParams, +}); + +export type RuleResponseOsqueryAction = z.infer; +export const RuleResponseOsqueryAction = z.object({ + actionTypeId: z.literal('.osquery'), + params: OsqueryParamsCamelCase, +}); + +export type EndpointParams = z.infer; +export const EndpointParams = z + .object({ + command: z.literal('isolate'), + comment: z.string().optional(), + }) + .transform(requiredOptional); + +export type EndpointResponseAction = z.infer; +export const EndpointResponseAction = z.object({ + action_type_id: z.literal('.endpoint'), + params: EndpointParams, +}); + +export type RuleResponseEndpointAction = z.infer; +export const RuleResponseEndpointAction = z.object({ + actionTypeId: z.literal('.endpoint'), + params: EndpointParams, +}); + +export type ResponseAction = z.infer; +export const ResponseAction = z.union([OsqueryResponseAction, EndpointResponseAction]); + +export type RuleResponseAction = z.infer; +export const RuleResponseAction = z.union([RuleResponseOsqueryAction, RuleResponseEndpointAction]); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml new file mode 100644 index 00000000000000..6cc6f0c46465cd --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.schema.yaml @@ -0,0 +1,164 @@ +openapi: 3.0.0 +info: + title: Response Actions Schema + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + ResponseActionTypes: + type: string + enum: + - .osquery + - .endpoint + + EcsMapping: + type: object + additionalProperties: + type: object + properties: + field: + type: string + value: + oneOf: + - type: string + - type: array + items: + type: string + + OsqueryQuery: + type: object + properties: + id: + type: string + description: Query ID + query: + type: string + description: Query to execute + ecs_mapping: + $ref: '#/components/schemas/EcsMapping' + version: + type: string + description: Query version + platform: + type: string + removed: + type: boolean + snapshot: + type: boolean + required: + - id + - query + x-modify: requiredOptional + + OsqueryParams: + type: object + properties: + query: + type: string + ecs_mapping: + $ref: '#/components/schemas/EcsMapping' + queries: + type: array + items: + $ref: '#/components/schemas/OsqueryQuery' + pack_id: + type: string + saved_query_id: + type: string + x-modify: requiredOptional + + OsqueryParamsCamelCase: + type: object + properties: + query: + type: string + ecsMapping: + $ref: '#/components/schemas/EcsMapping' + queries: + type: array + items: + $ref: '#/components/schemas/OsqueryQuery' + packId: + type: string + savedQueryId: + type: string + x-modify: requiredOptional + + OsqueryResponseAction: + type: object + properties: + action_type_id: + type: string + enum: + - .osquery + params: + $ref: '#/components/schemas/OsqueryParams' + required: + - action_type_id + - params + + # Camel cased versions of OsqueryResponseAction + RuleResponseOsqueryAction: + type: object + properties: + actionTypeId: + type: string + enum: + - .osquery + params: + $ref: '#/components/schemas/OsqueryParamsCamelCase' + required: + - actionTypeId + - params + + EndpointParams: + type: object + properties: + command: + type: string + enum: + - isolate + comment: + type: string + required: + - command + x-modify: requiredOptional + + EndpointResponseAction: + type: object + properties: + action_type_id: + type: string + enum: + - .endpoint + params: + $ref: '#/components/schemas/EndpointParams' + required: + - action_type_id + - params + + # Camel cased versions of EndpointResponseAction + RuleResponseEndpointAction: + type: object + properties: + actionTypeId: + type: string + enum: + - .endpoint + params: + $ref: '#/components/schemas/EndpointParams' + required: + - actionTypeId + - params + + ResponseAction: + oneOf: + - $ref: '#/components/schemas/OsqueryResponseAction' + - $ref: '#/components/schemas/EndpointResponseAction' + + # Camel Cased versions of ResponseAction + RuleResponseAction: + oneOf: + - $ref: '#/components/schemas/RuleResponseOsqueryAction' + - $ref: '#/components/schemas/RuleResponseEndpointAction' diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.ts deleted file mode 100644 index 335a5f91ffbc5e..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions.ts +++ /dev/null @@ -1,60 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { EndpointParams } from './endpoint'; -import { OsqueryParams, OsqueryParamsCamelCase } from './osquery'; - -export enum RESPONSE_ACTION_TYPES { - OSQUERY = '.osquery', - ENDPOINT = '.endpoint', -} - -export const SUPPORTED_RESPONSE_ACTION_TYPES = Object.values(RESPONSE_ACTION_TYPES); - -// When we create new response action types, create a union of types -export const OsqueryResponseActionRuleParam = t.strict({ - actionTypeId: t.literal(RESPONSE_ACTION_TYPES.OSQUERY), - params: OsqueryParamsCamelCase, -}); - -export type RuleResponseOsqueryAction = t.TypeOf; - -export const EndpointResponseActionRuleParam = t.strict({ - actionTypeId: t.literal(RESPONSE_ACTION_TYPES.ENDPOINT), - params: EndpointParams, -}); - -export type RuleResponseEndpointAction = t.TypeOf; - -const ResponseActionRuleParam = t.union([ - OsqueryResponseActionRuleParam, - EndpointResponseActionRuleParam, -]); -export type RuleResponseAction = t.TypeOf; - -export const ResponseActionRuleParamsOrUndefined = t.union([ - t.array(ResponseActionRuleParam), - t.undefined, -]); - -// When we create new response action types, create a union of types -const OsqueryResponseAction = t.strict({ - action_type_id: t.literal(RESPONSE_ACTION_TYPES.OSQUERY), - params: OsqueryParams, -}); - -const EndpointResponseAction = t.strict({ - action_type_id: t.literal(RESPONSE_ACTION_TYPES.ENDPOINT), - params: EndpointParams, -}); - -const ResponseAction = t.union([OsqueryResponseAction, EndpointResponseAction]); - -export const ResponseActionArray = t.array(ResponseAction); - -export type ResponseAction = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions_legacy.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions_legacy.ts new file mode 100644 index 00000000000000..6947953b4d65d0 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_response_actions/response_actions_legacy.ts @@ -0,0 +1,82 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { arrayQueries, ecsMapping } from '@kbn/osquery-io-ts-types'; +import * as t from 'io-ts'; +import { ENABLED_AUTOMATED_RESPONSE_ACTION_COMMANDS } from '../../../../endpoint/service/response_actions/constants'; +import { ResponseActionTypesEnum } from './response_actions.gen'; + +export const RESPONSE_ACTION_TYPES = { + OSQUERY: ResponseActionTypesEnum['.osquery'], + ENDPOINT: ResponseActionTypesEnum['.endpoint'], +} as const; + +export const SUPPORTED_RESPONSE_ACTION_TYPES = Object.values(RESPONSE_ACTION_TYPES); + +// to enable using RESPONSE_ACTION_API_COMMANDS_NAMES as a type +function keyObject(arr: T): { [K in T[number]]: null } { + return Object.fromEntries(arr.map((v) => [v, null])) as never; +} + +export type EndpointParams = t.TypeOf; +export const EndpointParams = t.type({ + command: t.keyof(keyObject(ENABLED_AUTOMATED_RESPONSE_ACTION_COMMANDS)), + comment: t.union([t.string, t.undefined]), +}); + +export const OsqueryParams = t.type({ + query: t.union([t.string, t.undefined]), + ecs_mapping: t.union([ecsMapping, t.undefined]), + queries: t.union([arrayQueries, t.undefined]), + pack_id: t.union([t.string, t.undefined]), + saved_query_id: t.union([t.string, t.undefined]), +}); + +export const OsqueryParamsCamelCase = t.type({ + query: t.union([t.string, t.undefined]), + ecsMapping: t.union([ecsMapping, t.undefined]), + queries: t.union([arrayQueries, t.undefined]), + packId: t.union([t.string, t.undefined]), + savedQueryId: t.union([t.string, t.undefined]), +}); + +// When we create new response action types, create a union of types +export type RuleResponseOsqueryAction = t.TypeOf; +export const RuleResponseOsqueryAction = t.strict({ + actionTypeId: t.literal(RESPONSE_ACTION_TYPES.OSQUERY), + params: OsqueryParamsCamelCase, +}); + +export type RuleResponseEndpointAction = t.TypeOf; +export const RuleResponseEndpointAction = t.strict({ + actionTypeId: t.literal(RESPONSE_ACTION_TYPES.ENDPOINT), + params: EndpointParams, +}); + +export type RuleResponseAction = t.TypeOf; +const ResponseActionRuleParam = t.union([RuleResponseOsqueryAction, RuleResponseEndpointAction]); + +export const ResponseActionRuleParamsOrUndefined = t.union([ + t.array(ResponseActionRuleParam), + t.undefined, +]); + +// When we create new response action types, create a union of types +const OsqueryResponseAction = t.strict({ + action_type_id: t.literal(RESPONSE_ACTION_TYPES.OSQUERY), + params: OsqueryParams, +}); + +const EndpointResponseAction = t.strict({ + action_type_id: t.literal(RESPONSE_ACTION_TYPES.ENDPOINT), + params: EndpointParams, +}); + +export type ResponseAction = t.TypeOf; +export const ResponseAction = t.union([OsqueryResponseAction, EndpointResponseAction]); + +export const ResponseActionArray = t.array(ResponseAction); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/build_rule_schemas.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/build_rule_schemas.ts deleted file mode 100644 index c77ba322b1c79b..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/build_rule_schemas.ts +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; - -interface RuleFields< - Required extends t.Props, - Optional extends t.Props, - Defaultable extends t.Props -> { - required: Required; - optional: Optional; - defaultable: Defaultable; -} - -export const buildRuleSchemas = ( - fields: RuleFields -) => { - return { - ...fields, - create: buildCreateRuleSchema(fields.required, fields.optional, fields.defaultable), - patch: buildPatchRuleSchema(fields.required, fields.optional, fields.defaultable), - response: buildResponseRuleSchema(fields.required, fields.optional, fields.defaultable), - }; -}; - -const buildCreateRuleSchema = < - Required extends t.Props, - Optional extends t.Props, - Defaultable extends t.Props ->( - requiredFields: Required, - optionalFields: Optional, - defaultableFields: Defaultable -) => { - return t.intersection([ - t.exact(t.type(requiredFields)), - t.exact(t.partial(optionalFields)), - t.exact(t.partial(defaultableFields)), - ]); -}; - -const buildPatchRuleSchema = < - Required extends t.Props, - Optional extends t.Props, - Defaultable extends t.Props ->( - requiredFields: Required, - optionalFields: Optional, - defaultableFields: Defaultable -) => { - return t.intersection([ - t.partial(requiredFields), - t.partial(optionalFields), - t.partial(defaultableFields), - ]); -}; - -export type OrUndefined

= { - [K in keyof P]: P[K] | t.UndefinedC; -}; - -export const orUndefined =

(props: P): OrUndefined

=> { - return Object.keys(props).reduce((acc, key) => { - acc[key] = t.union([props[key], t.undefined]); - return acc; - }, {}) as OrUndefined

; -}; - -export const buildResponseRuleSchema = < - Required extends t.Props, - Optional extends t.Props, - Defaultable extends t.Props ->( - requiredFields: Required, - optionalFields: Optional, - defaultableFields: Defaultable -) => { - // This bit of logic is to force all fields to be accounted for in conversions from the internal - // rule schema to the response schema. Rather than use `t.partial`, which makes each field optional, - // we make each field required but possibly undefined. The result is that if a field is forgotten in - // the conversion from internal schema to response schema TS will report an error. If we just used t.partial - // instead, then optional fields can be accidentally omitted from the conversion - and any actual values - // in those fields internally will be stripped in the response. - const optionalWithUndefined = orUndefined(optionalFields); - return t.intersection([ - t.exact(t.type(requiredFields)), - t.exact(t.type(optionalWithUndefined)), - t.exact(t.type(defaultableFields)), - ]); -}; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts index 5ce6fe1bc4727c..0d62dfd9c21f30 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.gen.ts @@ -6,20 +6,30 @@ */ import { z } from 'zod'; +import { requiredOptional, isValidDateMath } from '@kbn/zod-helpers'; /* * NOTICE: Do not edit this file manually. * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. */ +/** + * A string that is not empty and does not contain only whitespace + */ +export type NonEmptyString = z.infer; +export const NonEmptyString = z + .string() + .min(1) + .regex(/^(?! *$).+$/); + /** * A universally unique identifier */ export type UUID = z.infer; -export const UUID = z.string(); +export const UUID = z.string().uuid(); export type RuleObjectId = z.infer; -export const RuleObjectId = z.string(); +export const RuleObjectId = UUID; /** * Could be any string, not necessarily a UUID @@ -33,21 +43,100 @@ export const RuleName = z.string().min(1); export type RuleDescription = z.infer; export const RuleDescription = z.string().min(1); +/** + * The rule's version number. + */ export type RuleVersion = z.infer; -export const RuleVersion = z.string(); +export const RuleVersion = z.number().int().min(1); + +export type QueryLanguage = z.infer; +export const QueryLanguage = z.enum(['kuery', 'lucene', 'eql', 'esql']); +export type QueryLanguageEnum = typeof QueryLanguage.enum; +export const QueryLanguageEnum = QueryLanguage.enum; + +export type KqlQueryLanguage = z.infer; +export const KqlQueryLanguage = z.enum(['kuery', 'lucene']); +export type KqlQueryLanguageEnum = typeof KqlQueryLanguage.enum; +export const KqlQueryLanguageEnum = KqlQueryLanguage.enum; export type IsRuleImmutable = z.infer; export const IsRuleImmutable = z.boolean(); +/** + * Determines whether the rule is enabled. + */ export type IsRuleEnabled = z.infer; export const IsRuleEnabled = z.boolean(); +/** + * Frequency of rule execution, using a date math range. For example, "1h" means the rule runs every hour. Defaults to 5m (5 minutes). + */ +export type RuleInterval = z.infer; +export const RuleInterval = z.string(); + +/** + * Time from which data is analyzed each time the rule executes, using a date math range. For example, now-4200s means the rule analyzes data from 70 minutes before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). + */ +export type RuleIntervalFrom = z.infer; +export const RuleIntervalFrom = z.string().superRefine(isValidDateMath); + +export type RuleIntervalTo = z.infer; +export const RuleIntervalTo = z.string(); + +/** + * Risk score (0 to 100) + */ +export type RiskScore = z.infer; +export const RiskScore = z.number().int().min(0).max(100); + +/** + * Overrides generated alerts' risk_score with a value from the source event + */ +export type RiskScoreMapping = z.infer; +export const RiskScoreMapping = z.array( + z + .object({ + field: z.string(), + operator: z.literal('equals'), + value: z.string(), + risk_score: RiskScore.optional(), + }) + .transform(requiredOptional) +); + +/** + * Severity of the rule + */ +export type Severity = z.infer; +export const Severity = z.enum(['low', 'medium', 'high', 'critical']); +export type SeverityEnum = typeof Severity.enum; +export const SeverityEnum = Severity.enum; + +/** + * Overrides generated alerts' severity with values from the source event + */ +export type SeverityMapping = z.infer; +export const SeverityMapping = z.array( + z.object({ + field: z.string(), + operator: z.literal('equals'), + severity: Severity, + value: z.string(), + }) +); + +/** + * String array containing words and phrases to help categorize, filter, and search rules. Defaults to an empty array. + */ export type RuleTagArray = z.infer; export const RuleTagArray = z.array(z.string()); export type RuleMetadata = z.infer; -export const RuleMetadata = z.object({}); +export const RuleMetadata = z.object({}).catchall(z.unknown()); +/** + * The rule's license. + */ export type RuleLicense = z.infer; export const RuleLicense = z.string(); @@ -60,26 +149,38 @@ export const RuleFalsePositiveArray = z.array(z.string()); export type RuleReferenceArray = z.infer; export const RuleReferenceArray = z.array(z.string()); +/** + * Notes to help investigate alerts produced by the rule. + */ export type InvestigationGuide = z.infer; export const InvestigationGuide = z.string(); export type SetupGuide = z.infer; export const SetupGuide = z.string(); +/** + * Determines if the rule acts as a building block. By default, building-block alerts are not displayed in the UI. These rules are used as a foundation for other rules that do generate alerts. Its value must be default. + */ export type BuildingBlockType = z.infer; export const BuildingBlockType = z.string(); +/** + * (deprecated) Has no effect. + */ export type AlertsIndex = z.infer; export const AlertsIndex = z.string(); +/** + * Has no effect. + */ export type AlertsIndexNamespace = z.infer; export const AlertsIndexNamespace = z.string(); export type MaxSignals = z.infer; export const MaxSignals = z.number().int().min(1); -export type Subtechnique = z.infer; -export const Subtechnique = z.object({ +export type ThreatSubtechnique = z.infer; +export const ThreatSubtechnique = z.object({ /** * Subtechnique ID */ @@ -94,8 +195,8 @@ export const Subtechnique = z.object({ reference: z.string(), }); -export type Technique = z.infer; -export const Technique = z.object({ +export type ThreatTechnique = z.infer; +export const ThreatTechnique = z.object({ /** * Technique ID */ @@ -111,7 +212,23 @@ export const Technique = z.object({ /** * Array containing more specific information on the attack technique */ - subtechnique: z.array(Subtechnique).optional(), + subtechnique: z.array(ThreatSubtechnique).optional(), +}); + +export type ThreatTactic = z.infer; +export const ThreatTactic = z.object({ + /** + * Tactic ID + */ + id: z.string(), + /** + * Tactic name + */ + name: z.string(), + /** + * Tactic reference + */ + reference: z.string(), }); export type Threat = z.infer; @@ -120,24 +237,11 @@ export const Threat = z.object({ * Relevant attack framework */ framework: z.string(), - tactic: z.object({ - /** - * Tactic ID - */ - id: z.string(), - /** - * Tactic name - */ - name: z.string(), - /** - * Tactic reference - */ - reference: z.string(), - }), + tactic: ThreatTactic, /** * Array containing information on the attack techniques (optional) */ - technique: z.array(Technique).optional(), + technique: z.array(ThreatTechnique).optional(), }); export type ThreatArray = z.infer; @@ -149,41 +253,59 @@ export const IndexPatternArray = z.array(z.string()); export type DataViewId = z.infer; export const DataViewId = z.string(); +export type SavedQueryId = z.infer; +export const SavedQueryId = z.string(); + export type RuleQuery = z.infer; export const RuleQuery = z.string(); export type RuleFilterArray = z.infer; -export const RuleFilterArray = z.array(z.object({})); +export const RuleFilterArray = z.array(z.unknown()); +/** + * Sets the source field for the alert's signal.rule.name value + */ export type RuleNameOverride = z.infer; export const RuleNameOverride = z.string(); +/** + * Sets the time field used to query indices + */ export type TimestampOverride = z.infer; export const TimestampOverride = z.string(); +/** + * Disables the fallback to the event's @timestamp field + */ export type TimestampOverrideFallbackDisabled = z.infer; export const TimestampOverrideFallbackDisabled = z.boolean(); export type RequiredField = z.infer; export const RequiredField = z.object({ - name: z.string().min(1).optional(), - type: z.string().min(1).optional(), - ecs: z.boolean().optional(), + name: NonEmptyString, + type: NonEmptyString, + ecs: z.boolean(), }); export type RequiredFieldArray = z.infer; export const RequiredFieldArray = z.array(RequiredField); +/** + * Timeline template ID + */ export type TimelineTemplateId = z.infer; export const TimelineTemplateId = z.string(); +/** + * Timeline template title + */ export type TimelineTemplateTitle = z.infer; export const TimelineTemplateTitle = z.string(); export type SavedObjectResolveOutcome = z.infer; export const SavedObjectResolveOutcome = z.enum(['exactMatch', 'aliasMatch', 'conflict']); -export const SavedObjectResolveOutcomeEnum = SavedObjectResolveOutcome.enum; export type SavedObjectResolveOutcomeEnum = typeof SavedObjectResolveOutcome.enum; +export const SavedObjectResolveOutcomeEnum = SavedObjectResolveOutcome.enum; export type SavedObjectResolveAliasTargetId = z.infer; export const SavedObjectResolveAliasTargetId = z.string(); @@ -193,15 +315,110 @@ export const SavedObjectResolveAliasPurpose = z.enum([ 'savedObjectConversion', 'savedObjectImport', ]); -export const SavedObjectResolveAliasPurposeEnum = SavedObjectResolveAliasPurpose.enum; export type SavedObjectResolveAliasPurposeEnum = typeof SavedObjectResolveAliasPurpose.enum; +export const SavedObjectResolveAliasPurposeEnum = SavedObjectResolveAliasPurpose.enum; export type RelatedIntegration = z.infer; export const RelatedIntegration = z.object({ - package: z.string().min(1), - version: z.string().min(1), - integration: z.string().min(1).optional(), + package: NonEmptyString, + version: NonEmptyString, + integration: NonEmptyString.optional(), }); export type RelatedIntegrationArray = z.infer; export const RelatedIntegrationArray = z.array(RelatedIntegration); + +export type InvestigationFields = z.infer; +export const InvestigationFields = z.object({ + field_names: z.array(NonEmptyString).min(1), +}); + +/** + * Defines the interval on which a rule's actions are executed. + */ +export type RuleActionThrottle = z.infer; +export const RuleActionThrottle = z.union([ + z.enum(['no_actions', 'rule']), + z.string().regex(/^[1-9]\d*[smhd]$/), +]); + +/** + * The condition for throttling the notification: `onActionGroupChange`, `onActiveAlert`, or `onThrottleInterval` + */ +export type RuleActionNotifyWhen = z.infer; +export const RuleActionNotifyWhen = z.enum([ + 'onActiveAlert', + 'onThrottleInterval', + 'onActionGroupChange', +]); +export type RuleActionNotifyWhenEnum = typeof RuleActionNotifyWhen.enum; +export const RuleActionNotifyWhenEnum = RuleActionNotifyWhen.enum; + +/** + * The action frequency defines when the action runs (for example, only on rule execution or at specific time intervals). + */ +export type RuleActionFrequency = z.infer; +export const RuleActionFrequency = z.object({ + /** + * Action summary indicates whether we will send a summary notification about all the generate alerts or notification per individual alert + */ + summary: z.boolean(), + notifyWhen: RuleActionNotifyWhen, + throttle: RuleActionThrottle.nullable(), +}); + +export type RuleAction = z.infer; +export const RuleAction = z.object({ + /** + * The action type used for sending notifications. + */ + action_type_id: z.string(), + /** + * Optionally groups actions by use cases. Use `default` for alert notifications. + */ + group: z.string(), + /** + * The connector ID. + */ + id: z.string(), + /** + * Object containing the allowed connector fields, which varies according to the connector type. + */ + params: z.object({}).catchall(z.unknown()), + uuid: NonEmptyString.optional(), + alerts_filter: z.object({}).catchall(z.unknown()).optional(), + frequency: RuleActionFrequency.optional(), +}); + +/** + * The exception type + */ +export type ExceptionListType = z.infer; +export const ExceptionListType = z.enum([ + 'detection', + 'rule_default', + 'endpoint', + 'endpoint_trusted_apps', + 'endpoint_events', + 'endpoint_host_isolation_exceptions', + 'endpoint_blocklists', +]); +export type ExceptionListTypeEnum = typeof ExceptionListType.enum; +export const ExceptionListTypeEnum = ExceptionListType.enum; + +export type RuleExceptionList = z.infer; +export const RuleExceptionList = z.object({ + /** + * ID of the exception container + */ + id: NonEmptyString, + /** + * List ID of the exception container + */ + list_id: NonEmptyString, + type: ExceptionListType, + /** + * Determines the exceptions validity in rule's Kibana space + */ + namespace_type: z.enum(['agnostic', 'single']), +}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml index 52d59c3a656d60..921f9350550b6c 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.schema.yaml @@ -6,13 +6,19 @@ paths: {} components: x-codegen-enabled: true schemas: + NonEmptyString: + type: string + pattern: ^(?! *$).+$ + minLength: 1 + description: A string that is not empty and does not contain only whitespace + UUID: type: string format: uuid description: A universally unique identifier RuleObjectId: - type: string + $ref: '#/components/schemas/UUID' RuleSignatureId: type: string @@ -27,19 +33,103 @@ components: minLength: 1 RuleVersion: + type: integer + minimum: 1 + description: The rule's version number. + + QueryLanguage: type: string - format: version + enum: + - kuery + - lucene + - eql + - esql + + KqlQueryLanguage: + type: string + enum: + - kuery + - lucene IsRuleImmutable: type: boolean IsRuleEnabled: type: boolean + description: Determines whether the rule is enabled. + + RuleInterval: + type: string + description: Frequency of rule execution, using a date math range. For example, "1h" means the rule runs every hour. Defaults to 5m (5 minutes). + + RuleIntervalFrom: + type: string + description: Time from which data is analyzed each time the rule executes, using a date math range. For example, now-4200s means the rule analyzes data from 70 minutes before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). + format: date-math + + RuleIntervalTo: + type: string + + RiskScore: + type: integer + description: Risk score (0 to 100) + minimum: 0 + maximum: 100 + + RiskScoreMapping: + type: array + items: + type: object + properties: + field: + type: string + operator: + type: string + enum: + - equals + value: + type: string + risk_score: + $ref: '#/components/schemas/RiskScore' + required: + - field + - operator + - value + x-modify: requiredOptional + description: Overrides generated alerts' risk_score with a value from the source event + + Severity: + type: string + enum: [low, medium, high, critical] + description: Severity of the rule + + SeverityMapping: + type: array + items: + type: object + properties: + field: + type: string + operator: + type: string + enum: + - equals + severity: + $ref: '#/components/schemas/Severity' + value: + type: string + required: + - field + - operator + - severity + - value + description: Overrides generated alerts' severity with values from the source event RuleTagArray: type: array items: type: string + description: String array containing words and phrases to help categorize, filter, and search rules. Defaults to an empty array. RuleMetadata: type: object @@ -47,6 +137,7 @@ components: RuleLicense: type: string + description: The rule's license. RuleAuthorArray: type: array @@ -65,24 +156,29 @@ components: InvestigationGuide: type: string + description: Notes to help investigate alerts produced by the rule. SetupGuide: type: string BuildingBlockType: type: string + description: Determines if the rule acts as a building block. By default, building-block alerts are not displayed in the UI. These rules are used as a foundation for other rules that do generate alerts. Its value must be default. AlertsIndex: type: string + description: (deprecated) Has no effect. + deprecated: true AlertsIndexNamespace: type: string + description: Has no effect. MaxSignals: type: integer minimum: 1 - Subtechnique: + ThreatSubtechnique: type: object properties: id: @@ -99,7 +195,7 @@ components: - name - reference - Technique: + ThreatTechnique: type: object properties: id: @@ -114,13 +210,30 @@ components: subtechnique: type: array items: - $ref: '#/components/schemas/Subtechnique' + $ref: '#/components/schemas/ThreatSubtechnique' description: Array containing more specific information on the attack technique required: - id - name - reference + ThreatTactic: + type: object + properties: + id: + type: string + description: Tactic ID + name: + type: string + description: Tactic name + reference: + type: string + description: Tactic reference + required: + - id + - name + - reference + Threat: type: object properties: @@ -128,25 +241,11 @@ components: type: string description: Relevant attack framework tactic: - type: object - properties: - id: - type: string - description: Tactic ID - name: - type: string - description: Tactic name - reference: - type: string - description: Tactic reference - required: - - id - - name - - reference + $ref: '#/components/schemas/ThreatTactic' technique: type: array items: - $ref: '#/components/schemas/Technique' + $ref: '#/components/schemas/ThreatTechnique' description: Array containing information on the attack techniques (optional) required: - framework @@ -155,7 +254,7 @@ components: ThreatArray: type: array items: - $ref: '#/components/schemas/Threat' # Assuming a schema named 'Threat' is defined in the components section. + $ref: '#/components/schemas/Threat' IndexPatternArray: type: array @@ -165,35 +264,41 @@ components: DataViewId: type: string + SavedQueryId: + type: string + RuleQuery: type: string RuleFilterArray: type: array - items: - type: object - additionalProperties: true + items: {} # unknown RuleNameOverride: type: string + description: Sets the source field for the alert's signal.rule.name value TimestampOverride: type: string + description: Sets the time field used to query indices TimestampOverrideFallbackDisabled: type: boolean + description: Disables the fallback to the event's @timestamp field RequiredField: type: object properties: name: - type: string - minLength: 1 + $ref: '#/components/schemas/NonEmptyString' type: - type: string - minLength: 1 + $ref: '#/components/schemas/NonEmptyString' ecs: type: boolean + required: + - name + - type + - ecs RequiredFieldArray: type: array @@ -202,9 +307,11 @@ components: TimelineTemplateId: type: string + description: Timeline template ID TimelineTemplateTitle: type: string + description: Timeline template title SavedObjectResolveOutcome: type: string @@ -226,14 +333,11 @@ components: type: object properties: package: - type: string - minLength: 1 + $ref: '#/components/schemas/NonEmptyString' version: - type: string - minLength: 1 + $ref: '#/components/schemas/NonEmptyString' integration: - type: string - minLength: 1 + $ref: '#/components/schemas/NonEmptyString' required: - package - version @@ -242,3 +346,117 @@ components: type: array items: $ref: '#/components/schemas/RelatedIntegration' + + # Schema for fields relating to investigation fields, these are user defined fields we use to highlight in various features in the UI such as alert details flyout and exceptions auto-population from alert. Added in PR #163235 + # Right now we only have a single field but anticipate adding more related fields to store various configuration states such as `override` - where a user might say if they want only these fields to display, or if they want these fields + the fields we select. + InvestigationFields: + type: object + properties: + field_names: + type: array + items: + $ref: '#/components/schemas/NonEmptyString' + minItems: 1 + required: + - field_names + + RuleActionThrottle: + description: Defines the interval on which a rule's actions are executed. + oneOf: + - type: string + enum: + - 'no_actions' + - 'rule' + - type: string + pattern: '^[1-9]\d*[smhd]$' # any number except zero followed by one of the suffixes 's', 'm', 'h', 'd' + description: Time interval in seconds, minutes, hours, or days. + example: '1h' + + RuleActionNotifyWhen: + type: string + enum: + - 'onActiveAlert' + - 'onThrottleInterval' + - 'onActionGroupChange' + description: 'The condition for throttling the notification: `onActionGroupChange`, `onActiveAlert`, or `onThrottleInterval`' + + RuleActionFrequency: + type: object + description: The action frequency defines when the action runs (for example, only on rule execution or at specific time intervals). + properties: + summary: + type: boolean + description: Action summary indicates whether we will send a summary notification about all the generate alerts or notification per individual alert + notifyWhen: + $ref: '#/components/schemas/RuleActionNotifyWhen' + throttle: + $ref: '#/components/schemas/RuleActionThrottle' + nullable: true + required: + - summary + - notifyWhen + - throttle + + RuleAction: + type: object + properties: + action_type_id: + type: string + description: The action type used for sending notifications. + group: + type: string + description: Optionally groups actions by use cases. Use `default` for alert notifications. + id: + type: string + description: The connector ID. + params: + type: object + description: Object containing the allowed connector fields, which varies according to the connector type. + additionalProperties: true + uuid: + $ref: '#/components/schemas/NonEmptyString' + alerts_filter: + type: object + additionalProperties: true + frequency: + $ref: '#/components/schemas/RuleActionFrequency' + required: + - action_type_id + - group + - id + - params + + ExceptionListType: + type: string + description: The exception type + enum: + - detection + - rule_default + - endpoint + - endpoint_trusted_apps + - endpoint_events + - endpoint_host_isolation_exceptions + - endpoint_blocklists + + RuleExceptionList: + type: object + properties: + id: + $ref: '#/components/schemas/NonEmptyString' + description: ID of the exception container + list_id: + $ref: '#/components/schemas/NonEmptyString' + description: List ID of the exception container + type: + $ref: '#/components/schemas/ExceptionListType' + namespace_type: + type: string + description: Determines the exceptions validity in rule's Kibana space + enum: + - agnostic + - single + required: + - id + - list_id + - type + - namespace_type diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/index.ts index b184500990f1cd..1b4d506a806485 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/index.ts @@ -5,12 +5,12 @@ * 2.0. */ -export * from './common_attributes'; +export * from './common_attributes.gen'; +export * from './rule_schemas.gen'; -export * from './specific_attributes/eql_attributes'; -export * from './specific_attributes/new_terms_attributes'; -export * from './specific_attributes/query_attributes'; -export * from './specific_attributes/threshold_attributes'; - -export * from './rule_schemas'; -export * from './build_rule_schemas'; +export * from './specific_attributes/eql_attributes.gen'; +export * from './specific_attributes/ml_attributes.gen'; +export * from './specific_attributes/new_terms_attributes.gen'; +export * from './specific_attributes/query_attributes.gen'; +export * from './specific_attributes/threat_match_attributes.gen'; +export * from './specific_attributes/threshold_attributes.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.mock.ts index 1058c95bfcaac5..968199a9459a6d 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.mock.ts @@ -17,7 +17,7 @@ import type { ThresholdRuleCreateProps, NewTermsRuleCreateProps, NewTermsRuleUpdateProps, -} from './rule_schemas'; +} from './rule_schemas.gen'; export const getCreateRulesSchemaMock = (ruleId = 'rule-1'): QueryRuleCreateProps => ({ description: 'Detecting root and admin users', diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts index 765e10fa513bba..abbfa4903ea31e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_request_schema.test.ts @@ -5,47 +5,38 @@ * 2.0. */ -import * as t from 'io-ts'; -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { getListArrayMock } from '../../../../detection_engine/schemas/types/lists.mock'; -import type { SavedQueryRuleCreateProps } from './rule_schemas'; -import { RuleCreateProps } from './rule_schemas'; import { + getCreateEsqlRulesSchemaMock, + getCreateMachineLearningRulesSchemaMock, + getCreateRulesSchemaMock, + getCreateRulesSchemaMockWithDataView, getCreateSavedQueryRulesSchemaMock, getCreateThreatMatchRulesSchemaMock, - getCreateRulesSchemaMock, getCreateThresholdRulesSchemaMock, - getCreateRulesSchemaMockWithDataView, - getCreateMachineLearningRulesSchemaMock, - getCreateEsqlRulesSchemaMock, } from './rule_request_schema.mock'; -import { buildResponseRuleSchema } from './build_rule_schemas'; +import type { SavedQueryRuleCreateProps } from './rule_schemas.gen'; +import { RuleCreateProps } from './rule_schemas.gen'; describe('rules schema', () => { test('empty objects do not validate', () => { const payload = {}; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(message.errors.length).toBeGreaterThan(0); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); - test('made up values do not validate', () => { + test('strips any unknown values', () => { const payload: RuleCreateProps & { madeUp: string } = { ...getCreateRulesSchemaMock(), madeUp: 'hi', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(getCreateRulesSchemaMock()); }); test('[rule_id] does not validate', () => { @@ -53,11 +44,9 @@ describe('rules schema', () => { rule_id: 'rule-1', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(message.errors.length).toBeGreaterThan(0); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description] does not validate', () => { @@ -66,11 +55,9 @@ describe('rules schema', () => { description: 'some description', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(message.errors.length).toBeGreaterThan(0); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from] does not validate', () => { @@ -80,11 +67,9 @@ describe('rules schema', () => { from: 'now-5m', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(message.errors.length).toBeGreaterThan(0); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to] does not validate', () => { @@ -95,11 +80,9 @@ describe('rules schema', () => { to: 'now', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(message.errors.length).toBeGreaterThan(0); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to, name] does not validate', () => { @@ -111,11 +94,9 @@ describe('rules schema', () => { name: 'some-name', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(message.errors.length).toBeGreaterThan(0); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to, name, severity] does not validate', () => { @@ -128,11 +109,9 @@ describe('rules schema', () => { severity: 'low', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(message.errors.length).toBeGreaterThan(0); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to, name, severity, type] does not validate', () => { @@ -146,13 +125,9 @@ describe('rules schema', () => { type: 'query', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => { @@ -167,13 +142,9 @@ describe('rules schema', () => { type: 'query', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => { @@ -189,13 +160,9 @@ describe('rules schema', () => { index: ['index-1'], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to, name, severity, type, query, index, interval] does validate', () => { @@ -213,11 +180,9 @@ describe('rules schema', () => { interval: '5m', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does not validate', () => { @@ -235,13 +200,9 @@ describe('rules schema', () => { language: 'kuery', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score] does validate', () => { @@ -260,11 +221,9 @@ describe('rules schema', () => { language: 'kuery', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, output_index] does validate', () => { @@ -284,11 +243,9 @@ describe('rules schema', () => { language: 'kuery', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score] does validate', () => { @@ -305,11 +262,9 @@ describe('rules schema', () => { risk_score: 50, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index] does validate', () => { @@ -330,11 +285,9 @@ describe('rules schema', () => { type: 'query', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can send in a namespace', () => { @@ -343,11 +296,9 @@ describe('rules schema', () => { namespace: 'a namespace', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can send in an empty array to threat', () => { @@ -356,11 +307,9 @@ describe('rules schema', () => { threat: [], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index, threat] does validate', () => { @@ -395,11 +344,9 @@ describe('rules schema', () => { ], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('allows references to be sent as valid', () => { @@ -408,11 +355,9 @@ describe('rules schema', () => { references: ['index-1'], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('references cannot be numbers', () => { @@ -421,11 +366,9 @@ describe('rules schema', () => { references: [5], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "references"']); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('indexes cannot be numbers', () => { @@ -434,11 +377,9 @@ describe('rules schema', () => { index: [5], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "index"']); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('saved_query type can have filters with it', () => { @@ -447,11 +388,9 @@ describe('rules schema', () => { filters: [], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('filters cannot be a string', () => { @@ -460,13 +399,9 @@ describe('rules schema', () => { filters: 'some string', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "filters"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('language validates with kuery', () => { @@ -475,11 +410,9 @@ describe('rules schema', () => { language: 'kuery', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('language validates with lucene', () => { @@ -488,11 +421,9 @@ describe('rules schema', () => { language: 'lucene', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('language does not validate with something made up', () => { @@ -501,13 +432,9 @@ describe('rules schema', () => { language: 'something-made-up', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "something-made-up" supplied to "language"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('max_signals cannot be negative', () => { @@ -516,13 +443,11 @@ describe('rules schema', () => { max_signals: -1, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "max_signals"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'max_signals: Number must be greater than or equal to 1' + ); }); test('max_signals cannot be zero', () => { @@ -531,11 +456,11 @@ describe('rules schema', () => { max_signals: 0, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "0" supplied to "max_signals"']); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'max_signals: Number must be greater than or equal to 1' + ); }); test('max_signals can be 1', () => { @@ -544,11 +469,9 @@ describe('rules schema', () => { max_signals: 1, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can optionally send in an array of tags', () => { @@ -557,11 +480,9 @@ describe('rules schema', () => { tags: ['tag_1', 'tag_2'], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot send in an array of tags that are numbers', () => { @@ -570,15 +491,9 @@ describe('rules schema', () => { tags: [0, 1, 2], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "tags"', - 'Invalid value "1" supplied to "tags"', - 'Invalid value "2" supplied to "tags"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot send in an array of threat that are missing "framework"', () => { @@ -602,13 +517,9 @@ describe('rules schema', () => { ], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "threat,framework"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot send in an array of threat that are missing "tactic"', () => { @@ -628,13 +539,9 @@ describe('rules schema', () => { ], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "threat,tactic"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You can send in an array of threat that are missing "technique"', () => { @@ -652,11 +559,9 @@ describe('rules schema', () => { ], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can optionally send in an array of false positives', () => { @@ -665,11 +570,9 @@ describe('rules schema', () => { false_positives: ['false_1', 'false_2'], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot send in an array of false positives that are numbers', () => { @@ -678,27 +581,9 @@ describe('rules schema', () => { false_positives: [5, 4], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "false_positives"', - 'Invalid value "4" supplied to "false_positives"', - ]); - expect(message.schema).toEqual({}); - }); - - test('You cannot set the immutable to a number when trying to create a rule', () => { - const payload = { - ...getCreateRulesSchemaMock(), - immutable: 5, - }; - - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "immutable"']); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot set the risk_score to 101', () => { @@ -707,13 +592,11 @@ describe('rules schema', () => { risk_score: 101, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "101" supplied to "risk_score"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'risk_score: Number must be less than or equal to 100' + ); }); test('You cannot set the risk_score to -1', () => { @@ -722,11 +605,11 @@ describe('rules schema', () => { risk_score: -1, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "-1" supplied to "risk_score"']); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'risk_score: Number must be greater than or equal to 0' + ); }); test('You can set the risk_score to 0', () => { @@ -735,11 +618,9 @@ describe('rules schema', () => { risk_score: 0, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set the risk_score to 100', () => { @@ -748,11 +629,9 @@ describe('rules schema', () => { risk_score: 100, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set meta to any object you want', () => { @@ -763,11 +642,9 @@ describe('rules schema', () => { }, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot create meta as a string', () => { @@ -776,13 +653,9 @@ describe('rules schema', () => { meta: 'should not work', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "should not work" supplied to "meta"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You can omit the query string when filters are present', () => { @@ -792,11 +665,9 @@ describe('rules schema', () => { filters: [], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('validates with timeline_id and timeline_title', () => { @@ -806,11 +677,9 @@ describe('rules schema', () => { timeline_title: 'timeline-title', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot set the severity to a value other than low, medium, high, or critical', () => { @@ -819,11 +688,9 @@ describe('rules schema', () => { severity: 'junk', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "junk" supplied to "severity"']); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot send in an array of actions that are missing "group"', () => { @@ -832,13 +699,9 @@ describe('rules schema', () => { actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,group"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot send in an array of actions that are missing "id"', () => { @@ -847,13 +710,9 @@ describe('rules schema', () => { actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,id"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot send in an array of actions that are missing "action_type_id"', () => { @@ -862,13 +721,9 @@ describe('rules schema', () => { actions: [{ group: 'group', id: 'id', params: {} }], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,action_type_id"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot send in an array of actions that are missing "params"', () => { @@ -877,13 +732,9 @@ describe('rules schema', () => { actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,params"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot send in an array of actions that are including "actionTypeId"', () => { @@ -899,13 +750,9 @@ describe('rules schema', () => { ], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,action_type_id"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); describe('note', () => { @@ -915,11 +762,9 @@ describe('rules schema', () => { note: '# documentation markdown here', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set note to an empty string', () => { @@ -928,11 +773,9 @@ describe('rules schema', () => { note: '', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot create note as an object', () => { @@ -943,13 +786,9 @@ describe('rules schema', () => { }, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "{"somethingHere":"something else"}" supplied to "note"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('empty name is not valid', () => { @@ -958,11 +797,11 @@ describe('rules schema', () => { name: '', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "name"']); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'name: String must contain at least 1 character(s)' + ); }); test('empty description is not valid', () => { @@ -971,13 +810,11 @@ describe('rules schema', () => { description: '', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "" supplied to "description"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'description: String must contain at least 1 character(s)' + ); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note] does validate', () => { @@ -995,11 +832,9 @@ describe('rules schema', () => { note: '# some markdown', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); }); @@ -1026,46 +861,37 @@ describe('rules schema', () => { rule_id: 'rule-1', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('saved_id is required when type is saved_query and will not validate without it', () => { /* eslint-disable @typescript-eslint/naming-convention */ const { saved_id, ...payload } = getCreateSavedQueryRulesSchemaMock(); - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "saved_id"', - ]); - expect(message.schema).toEqual({}); + + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('threshold is required when type is threshold and will not validate without it', () => { const { threshold, ...payload } = getCreateThresholdRulesSchemaMock(); - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "threshold"', - ]); - expect(message.schema).toEqual({}); + + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('threshold rules fail validation if threshold is not greater than 0', () => { const payload = getCreateThresholdRulesSchemaMock(); payload.threshold.value = 0; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "threshold,value"', - ]); - expect(message.schema).toEqual({}); + + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'threshold.value: Number must be greater than or equal to 1' + ); }); describe('exception_list', () => { @@ -1086,11 +912,9 @@ describe('rules schema', () => { exceptions_list: getListArrayMock(), }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { @@ -1110,11 +934,9 @@ describe('rules schema', () => { exceptions_list: [], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, and invalid exceptions_list] does NOT validate', () => { @@ -1134,15 +956,9 @@ describe('rules schema', () => { exceptions_list: [{ id: 'uuid_here', namespace_type: 'not a namespace type' }], }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "exceptions_list,list_id"', - 'Invalid value "undefined" supplied to "exceptions_list,type"', - 'Invalid value "not a namespace type" supplied to "exceptions_list,namespace_type"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, and non-existent exceptions_list] does validate with empty exceptions_list', () => { @@ -1161,92 +977,87 @@ describe('rules schema', () => { note: '# some markdown', }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); }); describe('threat_match', () => { test('You can set a threat query, index, mapping, filters when creating a rule', () => { const payload = getCreateThreatMatchRulesSchemaMock(); - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('threat_index, threat_query, and threat_mapping are required when type is "threat_match" and validation fails without them', () => { /* eslint-disable @typescript-eslint/naming-convention */ const { threat_index, threat_query, threat_mapping, ...payload } = getCreateThreatMatchRulesSchemaMock(); - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "threat_query"', - 'Invalid value "undefined" supplied to "threat_mapping"', - 'Invalid value "undefined" supplied to "threat_index"', - ]); - expect(message.schema).toEqual({}); + + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('fails validation when threat_mapping is an empty array', () => { const payload = getCreateThreatMatchRulesSchemaMock(); payload.threat_mapping = []; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "[]" supplied to "threat_mapping"', - ]); - expect(message.schema).toEqual({}); + + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'threat_mapping: Array must contain at least 1 element(s)' + ); }); }); describe('esql rule type', () => { it('should validate correct payload', () => { const payload = getCreateEsqlRulesSchemaMock(); - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); - it('should not validate index property', () => { + + it('should drop the "index" property', () => { const payload = { ...getCreateEsqlRulesSchemaMock(), index: ['test*'] }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "index,["test*"]"']); + const expected = getCreateEsqlRulesSchemaMock(); + + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); - it('should not validate data_view_id property', () => { + + it('should drop the "data_view_id" property', () => { const payload = { ...getCreateEsqlRulesSchemaMock(), data_view_id: 'test' }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "data_view_id"']); + const expected = getCreateEsqlRulesSchemaMock(); + + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); - it('should not validate filters property', () => { + + it('should drop the "filters" property', () => { const payload = { ...getCreateEsqlRulesSchemaMock(), filters: [] }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "filters,[]"']); + const expected = getCreateEsqlRulesSchemaMock(); + + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); }); describe('data_view_id', () => { test('validates when "data_view_id" and index are defined', () => { const payload = { ...getCreateRulesSchemaMockWithDataView(), index: ['auditbeat-*'] }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('"data_view_id" cannot be a number', () => { @@ -1255,83 +1066,59 @@ describe('rules schema', () => { data_view_id: 5, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "data_view_id"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('it should validate a type of "query" with "data_view_id" defined', () => { const payload = getCreateRulesSchemaMockWithDataView(); - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = getCreateRulesSchemaMockWithDataView(); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should validate a type of "saved_query" with "data_view_id" defined', () => { const payload = { ...getCreateSavedQueryRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = { ...getCreateSavedQueryRulesSchemaMock(), data_view_id: 'logs-*' }; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should validate a type of "threat_match" with "data_view_id" defined', () => { const payload = { ...getCreateThreatMatchRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = { ...getCreateThreatMatchRulesSchemaMock(), data_view_id: 'logs-*' }; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should validate a type of "threshold" with "data_view_id" defined', () => { const payload = { ...getCreateThresholdRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = { ...getCreateThresholdRulesSchemaMock(), data_view_id: 'logs-*' }; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); - test('it should NOT validate a type of "machine_learning" with "data_view_id" defined', () => { + test('it should drop "data_view_id" when passed to "machine_learning" rules', () => { const payload = { ...getCreateMachineLearningRulesSchemaMock(), data_view_id: 'logs-*' }; + const expected = getCreateMachineLearningRulesSchemaMock(); - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(message.schema).toEqual({}); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "data_view_id"']); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); test('You can omit investigation_fields', () => { // getCreateRulesSchemaMock doesn't include investigation_fields const payload: RuleCreateProps = getCreateRulesSchemaMock(); - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot pass empty object for investigation_fields', () => { @@ -1342,13 +1129,9 @@ describe('rules schema', () => { investigation_fields: {}, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "investigation_fields,field_names"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You can send in investigation_fields', () => { @@ -1357,11 +1140,9 @@ describe('rules schema', () => { investigation_fields: { field_names: ['field1', 'field2'] }, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleCreateProps.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot send in an empty array of investigation_fields.field_names', () => { @@ -1370,13 +1151,11 @@ describe('rules schema', () => { investigation_fields: { field_names: [] }, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "[]" supplied to "investigation_fields,field_names"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'investigation_fields.field_names: Array must contain at least 1 element(s)' + ); }); test('You cannot send in an array of investigation_fields.field_names that are numbers', () => { @@ -1385,15 +1164,9 @@ describe('rules schema', () => { investigation_fields: { field_names: [0, 1, 2] }, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "investigation_fields,field_names"', - 'Invalid value "1" supplied to "investigation_fields,field_names"', - 'Invalid value "2" supplied to "investigation_fields,field_names"', - ]); - expect(message.schema).toEqual({}); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('You cannot send in investigation_fields without specifying fields', () => { @@ -1402,221 +1175,9 @@ describe('rules schema', () => { investigation_fields: { foo: true }, }; - const decoded = RuleCreateProps.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "investigation_fields,field_names"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('response', () => { - const testSchema = { - required: { - testRequiredString: t.string, - }, - optional: { - testOptionalString: t.string, - }, - defaultable: { - testDefaultableString: t.string, - }, - }; - const schema = buildResponseRuleSchema( - testSchema.required, - testSchema.optional, - testSchema.defaultable - ); - - describe('required fields', () => { - test('should allow required fields with the correct type', () => { - const payload = { - testRequiredString: 'required_string', - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('should not allow required fields to be undefined', () => { - const payload = { - testRequiredString: undefined, - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "testRequiredString"', - ]); - expect(message.schema).toEqual({}); - }); - - test('should not allow required fields to be omitted entirely', () => { - const payload = { - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "testRequiredString"', - ]); - expect(message.schema).toEqual({}); - }); - - test('should not allow required fields with an incorrect type', () => { - const payload = { - testRequiredString: 5, - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "testRequiredString"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('optional fields', () => { - test('should allow optional fields with the correct type', () => { - const payload: t.TypeOf = { - testRequiredString: 'required_string', - testOptionalString: 'optional_string', - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('should allow optional fields to be undefined', () => { - const payload: t.TypeOf = { - testRequiredString: 'required_string', - testOptionalString: undefined, - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('should allow optional fields to be omitted entirely', () => { - const payload = { - testRequiredString: 'required_string', - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('should not allow optional fields with an incorrect type', () => { - const payload = { - testRequiredString: 'required_string', - testOptionalString: 5, - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "testOptionalString"', - ]); - expect(message.schema).toEqual({}); - }); - }); - - describe('defaultable fields', () => { - test('should allow defaultable fields with the correct type', () => { - const payload = { - testRequiredString: 'required_string', - testDefaultableString: 'defaultable_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); - }); - - test('should not allow defaultable fields to be undefined', () => { - const payload = { - testRequiredString: 'required_string', - testDefaultableString: undefined, - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "testDefaultableString"', - ]); - expect(message.schema).toEqual({}); - }); - - test('should allow defaultable fields to be omitted entirely', () => { - const payload = { - testRequiredString: 'required_string', - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "testDefaultableString"', - ]); - expect(message.schema).toEqual({}); - }); - - test('should not allow defaultable fields with an incorrect type', () => { - const payload = { - testRequiredString: 'required_string', - testDefaultableString: 5, - }; - - const decoded = schema.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "testDefaultableString"', - ]); - expect(message.schema).toEqual({}); - }); + const result = RuleCreateProps.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.mock.ts index 19f1a1c44b8bc4..1a39d65c1c22f6 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.mock.ts @@ -14,7 +14,7 @@ import type { SavedQueryRule, SharedResponseProps, ThreatMatchRule, -} from './rule_schemas'; +} from './rule_schemas.gen'; import { getListArrayMock } from '../../../../detection_engine/schemas/types/lists.mock'; export const ANCHOR_DATE = '2020-02-20T03:57:54.037Z'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts index 40c01f83ebf4aa..e8573502cb662f 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_response_schema.test.ts @@ -4,12 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import { RuleResponse } from './rule_schemas'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; +import { RuleResponse } from './rule_schemas.gen'; import { getRulesSchemaMock, getRulesMlSchemaMock, @@ -23,37 +19,28 @@ describe('Rule response schema', () => { test('it should validate a type of "query" without anything extra', () => { const payload = getRulesSchemaMock(); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = getRulesSchemaMock(); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); - test('it should NOT validate a type of "query" when it has extra data', () => { + test('it should strip any extra data', () => { const payload: RuleResponse & { invalid_extra_data?: string } = getRulesSchemaMock(); payload.invalid_extra_data = 'invalid_extra_data'; + const expected = getRulesSchemaMock(); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); test('it should NOT validate invalid_data for the type', () => { const payload: Omit & { type: string } = getRulesSchemaMock(); payload.type = 'invalid_data'; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toHaveLength(1); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('it should validate a type of "query" with a saved_id together', () => { @@ -61,24 +48,17 @@ describe('Rule response schema', () => { payload.type = 'query'; payload.saved_id = 'save id 123'; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should validate a type of "saved_query" with a "saved_id" dependent', () => { const payload = getSavedQuerySchemaMock(); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = getSavedQuerySchemaMock(); - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should NOT validate a type of "saved_query" without a "saved_id" dependent', () => { @@ -86,27 +66,9 @@ describe('Rule response schema', () => { // @ts-expect-error delete payload.saved_id; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "saved_id"', - ]); - expect(message.schema).toEqual({}); - }); - - test('it should NOT validate a type of "saved_query" when it has extra data', () => { - const payload: RuleResponse & { saved_id?: string; invalid_extra_data?: string } = - getSavedQuerySchemaMock(); - payload.invalid_extra_data = 'invalid_extra_data'; - - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); test('it should validate a type of "timeline_id" if there is a "timeline_title" dependent', () => { @@ -114,42 +76,19 @@ describe('Rule response schema', () => { payload.timeline_id = 'some timeline id'; payload.timeline_title = 'some timeline title'; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = getRulesSchemaMock(); - expected.timeline_id = 'some timeline id'; - expected.timeline_title = 'some timeline title'; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); - }); - - test('it should NOT validate a type of "timeline_id" if there is "timeline_title" dependent when it has extra invalid data', () => { - const payload: RuleResponse & { invalid_extra_data?: string } = getRulesSchemaMock(); - payload.timeline_id = 'some timeline id'; - payload.timeline_title = 'some timeline title'; - payload.invalid_extra_data = 'invalid_extra_data'; - - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); describe('exceptions_list', () => { test('it should validate an empty array for "exceptions_list"', () => { const payload = getRulesSchemaMock(); payload.exceptions_list = []; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = getRulesSchemaMock(); - expected.exceptions_list = []; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should NOT validate when "exceptions_list" is not expected type', () => { @@ -157,49 +96,38 @@ describe('Rule response schema', () => { exceptions_list?: string; } = { ...getRulesSchemaMock(), exceptions_list: 'invalid_data' }; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "invalid_data" supplied to "exceptions_list"', - ]); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); }); describe('esql rule type', () => { - test('it should NOT validate a type of "esql" with "index" defined', () => { + test('it should omit the "index" field', () => { const payload = { ...getEsqlRuleSchemaMock(), index: ['logs-*'] }; + const expected = getEsqlRuleSchemaMock(); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "index,["logs-*"]"']); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); - test('it should NOT validate a type of "esql" with "filters" defined', () => { + test('it should omit the "filters" field', () => { const payload = { ...getEsqlRuleSchemaMock(), filters: [] }; + const expected = getEsqlRuleSchemaMock(); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "filters,[]"']); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); - test('it should NOT validate a type of "esql" with a "saved_id" dependent', () => { + test('it should omit the "saved_id" field', () => { const payload = { ...getEsqlRuleSchemaMock(), saved_id: 'id' }; + const expected = getEsqlRuleSchemaMock(); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "saved_id"']); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); }); @@ -207,13 +135,9 @@ describe('Rule response schema', () => { test('it should validate a type of "query" with "data_view_id" defined', () => { const payload = { ...getRulesSchemaMock(), data_view_id: 'logs-*' }; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = { ...getRulesSchemaMock(), data_view_id: 'logs-*' }; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should validate a type of "saved_query" with "data_view_id" defined', () => { @@ -221,149 +145,93 @@ describe('Rule response schema', () => { getSavedQuerySchemaMock(); payload.data_view_id = 'logs-*'; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected: RuleResponse & { saved_id?: string; data_view_id?: string } = - getSavedQuerySchemaMock(); - - expected.data_view_id = 'logs-*'; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should validate a type of "eql" with "data_view_id" defined', () => { const payload = { ...getRulesEqlSchemaMock(), data_view_id: 'logs-*' }; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = { ...getRulesEqlSchemaMock(), data_view_id: 'logs-*' }; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should validate a type of "threat_match" with "data_view_id" defined', () => { const payload = { ...getThreatMatchingSchemaMock(), data_view_id: 'logs-*' }; - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = { ...getThreatMatchingSchemaMock(), data_view_id: 'logs-*' }; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); - test('it should NOT validate a type of "machine_learning" with "data_view_id" defined', () => { + test('it should omit the "data_view_id" field for "machine_learning"rules', () => { const payload = { ...getRulesMlSchemaMock(), data_view_id: 'logs-*' }; + const expected = getRulesMlSchemaMock(); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "data_view_id"']); - expect(message.schema).toEqual({}); - }); - - test('it should NOT validate a type of "esql" with "data_view_id" defined', () => { - const payload = { ...getEsqlRuleSchemaMock(), data_view_id: 'logs-*' }; - - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual(['invalid keys "data_view_id"']); - expect(message.schema).toEqual({}); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); }); }); - describe('investigation_fields', () => { - test('it should validate rule with "investigation_fields"', () => { - const payload = getRulesSchemaMock(); - payload.investigation_fields = { field_names: ['foo', 'bar'] }; - - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = { - ...getRulesSchemaMock(), - investigation_fields: { field_names: ['foo', 'bar'] }, - }; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); - }); - - test('it should validate undefined for "investigation_fields"', () => { - const payload: RuleResponse = { - ...getRulesSchemaMock(), - investigation_fields: undefined, - }; + test('it should omit the "data_view_id" field for "esql" rules', () => { + const payload = { ...getEsqlRuleSchemaMock(), data_view_id: 'logs-*' }; + const expected = getEsqlRuleSchemaMock(); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = { ...getRulesSchemaMock(), investigation_fields: undefined }; - - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); - }); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(expected); + }); +}); - test('it should validate "investigation_fields" not in schema', () => { - const payload: RuleResponse = { - ...getRulesSchemaMock(), - investigation_fields: undefined, - }; +describe('investigation_fields', () => { + test('it should validate rule with "investigation_fields"', () => { + const payload = getRulesSchemaMock(); + payload.investigation_fields = { field_names: ['foo', 'bar'] }; - delete payload.investigation_fields; + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); + }); - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - const expected = getRulesSchemaMock(); + test('it should validate undefined for "investigation_fields"', () => { + const payload: RuleResponse = { + ...getRulesSchemaMock(), + investigation_fields: undefined, + }; - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(expected); - }); + const result = RuleResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); + }); - test('it should NOT validate an empty array for "investigation_fields.field_names"', () => { - const payload: RuleResponse = { - ...getRulesSchemaMock(), - investigation_fields: { - field_names: [], - }, - }; - - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "[]" supplied to "investigation_fields,field_names"', - 'Invalid value "{"field_names":[]}" supplied to "investigation_fields"', - ]); - expect(message.schema).toEqual({}); - }); + test('it should NOT validate an empty array for "investigation_fields.field_names"', () => { + const payload: RuleResponse = { + ...getRulesSchemaMock(), + investigation_fields: { + field_names: [], + }, + }; + + const result = RuleResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual( + 'investigation_fields.field_names: Array must contain at least 1 element(s)' + ); + }); - test('it should NOT validate a string for "investigation_fields"', () => { - const payload: Omit & { - investigation_fields: string; - } = { - ...getRulesSchemaMock(), - investigation_fields: 'foo', - }; - - const decoded = RuleResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "foo" supplied to "investigation_fields"', - ]); - expect(message.schema).toEqual({}); - }); + test('it should NOT validate a string for "investigation_fields"', () => { + const payload: Omit & { + investigation_fields: string; + } = { + ...getRulesSchemaMock(), + investigation_fields: 'foo', + }; + + const result = RuleResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toEqual('Invalid input'); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts index 4615a7b0b466f5..ff99655a75e890 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.gen.ts @@ -12,536 +12,645 @@ import { z } from 'zod'; * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. */ -export type Action = z.infer; -export const Action = z.object({ - /** - * The action type used for sending notifications. - */ - action_type_id: z.string(), - /** - * Optionally groups actions by use cases. Use `default` for alert notifications. - */ - group: z.string(), - /** - * The connector ID. - */ - id: z.string(), - /** - * Object containing the allowed connector fields, which varies according to the connector type. - */ - params: z.object({}), - uuid: z.string().optional(), - /** - * TODO implement the schema type - */ - alerts_filter: z.object({}).optional(), - /** - * TODO implement the schema type - */ - frequency: z.object({}).optional(), +import { + RuleName, + RuleDescription, + RiskScore, + Severity, + RuleNameOverride, + TimestampOverride, + TimestampOverrideFallbackDisabled, + TimelineTemplateId, + TimelineTemplateTitle, + SavedObjectResolveOutcome, + SavedObjectResolveAliasTargetId, + SavedObjectResolveAliasPurpose, + RuleLicense, + InvestigationGuide, + BuildingBlockType, + AlertsIndex, + AlertsIndexNamespace, + RuleMetadata, + InvestigationFields, + RuleActionThrottle, + RuleVersion, + RuleTagArray, + IsRuleEnabled, + RiskScoreMapping, + SeverityMapping, + RuleInterval, + RuleIntervalFrom, + RuleIntervalTo, + RuleAction, + RuleExceptionList, + RuleAuthorArray, + RuleFalsePositiveArray, + RuleReferenceArray, + MaxSignals, + ThreatArray, + RuleObjectId, + RuleSignatureId, + IsRuleImmutable, + RelatedIntegrationArray, + RequiredFieldArray, + SetupGuide, + RuleQuery, + IndexPatternArray, + DataViewId, + RuleFilterArray, + SavedQueryId, + KqlQueryLanguage, +} from './common_attributes.gen'; +import { RuleExecutionSummary } from '../../rule_monitoring/model/execution_summary.gen'; +import { + EventCategoryOverride, + TiebreakerField, + TimestampField, +} from './specific_attributes/eql_attributes.gen'; +import { ResponseAction } from '../rule_response_actions/response_actions.gen'; +import { AlertSuppression } from './specific_attributes/query_attributes.gen'; +import { Threshold } from './specific_attributes/threshold_attributes.gen'; +import { + ThreatQuery, + ThreatMapping, + ThreatIndex, + ThreatFilters, + ThreatIndicatorPath, + ConcurrentSearches, + ItemsPerSearch, +} from './specific_attributes/threat_match_attributes.gen'; +import { AnomalyThreshold, MachineLearningJobId } from './specific_attributes/ml_attributes.gen'; +import { NewTermsFields, HistoryWindowStart } from './specific_attributes/new_terms_attributes.gen'; + +export type BaseRequiredFields = z.infer; +export const BaseRequiredFields = z.object({ + name: RuleName, + description: RuleDescription, + risk_score: RiskScore, + severity: Severity, }); -export type AlertSuppression = z.infer; -export const AlertSuppression = z.object({ - group_by: z.array(z.string()).min(1).max(3), - duration: z - .object({ - value: z.number().int().min(1), - unit: z.enum(['s', 'm', 'h']), - }) - .optional(), - missing_fields_strategy: z.enum(['doNotSuppress', 'suppress']).optional(), +export type BaseOptionalFields = z.infer; +export const BaseOptionalFields = z.object({ + rule_name_override: RuleNameOverride.optional(), + timestamp_override: TimestampOverride.optional(), + timestamp_override_fallback_disabled: TimestampOverrideFallbackDisabled.optional(), + timeline_id: TimelineTemplateId.optional(), + timeline_title: TimelineTemplateTitle.optional(), + outcome: SavedObjectResolveOutcome.optional(), + alias_target_id: SavedObjectResolveAliasTargetId.optional(), + alias_purpose: SavedObjectResolveAliasPurpose.optional(), + license: RuleLicense.optional(), + note: InvestigationGuide.optional(), + building_block_type: BuildingBlockType.optional(), + output_index: AlertsIndex.optional(), + namespace: AlertsIndexNamespace.optional(), + meta: RuleMetadata.optional(), + investigation_fields: InvestigationFields.optional(), + throttle: RuleActionThrottle.optional(), }); -export type BaseRule = z.infer; -export const BaseRule = z.object({ - /** - * Rule name - */ - name: z.string(), - /** - * Rule description - */ - description: z.string(), - /** - * Risk score (0 to 100) - */ - risk_score: z.number().int().min(0).max(100), - /** - * Severity of the rule - */ - severity: z.enum(['low', 'medium', 'high', 'critical']), - /** - * Sets the source field for the alert's signal.rule.name value - */ - rule_name_override: z.string().optional(), - /** - * Sets the time field used to query indices (optional) - */ - timestamp_override: z.string().optional(), - /** - * Timeline template ID - */ - timeline_id: z.string().optional(), - /** - * Timeline template title - */ - timeline_title: z.string().optional(), - outcome: z.enum(['exactMatch', 'aliasMatch', 'conflict']).optional(), - /** - * TODO - */ - alias_target_id: z.string().optional(), - /** - * TODO - */ - alias_purpose: z.enum(['savedObjectConversion', 'savedObjectImport']).optional(), - /** - * The rule’s license. - */ - license: z.string().optional(), - /** - * Notes to help investigate alerts produced by the rule. - */ - note: z.string().optional(), - /** - * Determines if the rule acts as a building block. By default, building-block alerts are not displayed in the UI. These rules are used as a foundation for other rules that do generate alerts. Its value must be default. - */ - building_block_type: z.string().optional(), - /** - * (deprecated) Has no effect. - */ - output_index: z.string().optional(), - /** - * Has no effect. - */ - namespace: z.string().optional(), - /** - * Stores rule metadata. - */ - meta: z.object({}).optional(), - /** - * Defines the interval on which a rule's actions are executed. - */ - throttle: z.string().optional(), - /** - * The rule’s version number. Defaults to 1. - */ - version: z.number().int().min(1).optional().default(1), - /** - * String array containing words and phrases to help categorize, filter, and search rules. Defaults to an empty array. - */ - tags: z.array(z.string()).optional().default([]), - /** - * Determines whether the rule is enabled. Defaults to true. - */ - enabled: z.boolean().optional().default(true), - /** - * Overrides generated alerts' risk_score with a value from the source event - */ - risk_score_mapping: z - .array( - z.object({ - field: z.string(), - operator: z.enum(['equals']), - value: z.string(), - risk_score: z.number().int().min(0).max(100).optional(), - }) - ) - .optional() - .default([]), - /** - * Overrides generated alerts' severity with values from the source event - */ - severity_mapping: z - .array( - z.object({ - field: z.string(), - operator: z.enum(['equals']), - severity: z.enum(['low', 'medium', 'high', 'critical']), - value: z.string(), - }) - ) - .optional() - .default([]), - /** - * Frequency of rule execution, using a date math range. For example, "1h" means the rule runs every hour. Defaults to 5m (5 minutes). - */ - interval: z.string().optional().default('5m'), - /** - * Time from which data is analyzed each time the rule executes, using a date math range. For example, now-4200s means the rule analyzes data from 70 minutes before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). - */ - from: z.string().optional().default('now-6m'), - /** - * TODO - */ - to: z.string().optional().default('now'), - actions: z.array(Action).optional().default([]), - exceptions_list: z - .array( - z.object({ - /** - * ID of the exception container - */ - id: z.string().min(1), - /** - * List ID of the exception container - */ - list_id: z.string().min(1), - /** - * The exception type - */ - type: z.enum([ - 'detection', - 'rule_default', - 'endpoint', - 'endpoint_trusted_apps', - 'endpoint_events', - 'endpoint_host_isolation_exceptions', - 'endpoint_blocklists', - ]), - /** - * Determines the exceptions validity in rule's Kibana space - */ - namespace_type: z.enum(['agnostic', 'single']), - }) - ) - .optional() - .default([]), - author: z.array(z.string()).optional().default([]), - false_positives: z.array(z.string()).optional().default([]), - references: z.array(z.string()).optional().default([]), - max_signals: z.number().int().min(1).optional().default(100), - threat: z - .array( - z.object({ - /** - * Relevant attack framework - */ - framework: z.string(), - tactic: z.object({ - id: z.string(), - name: z.string(), - reference: z.string(), - }), - technique: z - .array( - z.object({ - id: z.string(), - name: z.string(), - reference: z.string(), - subtechnique: z - .array( - z.object({ - id: z.string(), - name: z.string(), - reference: z.string(), - }) - ) - .optional(), - }) - ) - .optional(), - }) - ) - .optional(), +export type BaseDefaultableFields = z.infer; +export const BaseDefaultableFields = z.object({ + version: RuleVersion.optional(), + tags: RuleTagArray.optional(), + enabled: IsRuleEnabled.optional(), + risk_score_mapping: RiskScoreMapping.optional(), + severity_mapping: SeverityMapping.optional(), + interval: RuleInterval.optional(), + from: RuleIntervalFrom.optional(), + to: RuleIntervalTo.optional(), + actions: z.array(RuleAction).optional(), + exceptions_list: z.array(RuleExceptionList).optional(), + author: RuleAuthorArray.optional(), + false_positives: RuleFalsePositiveArray.optional(), + references: RuleReferenceArray.optional(), + max_signals: MaxSignals.optional(), + threat: ThreatArray.optional(), }); -export type QueryRule = z.infer; -export const QueryRule = BaseRule.and( - z.object({ - /** - * Rule type - */ - type: z.enum(['query']), - index: z.array(z.string()).optional(), - data_view_id: z.string().optional(), - filters: z.array(z.unknown()).optional(), - saved_id: z.string().optional(), - /** - * TODO - */ - response_actions: z.array(z.object({})).optional(), - alert_suppression: AlertSuppression.optional(), - /** - * Query to execute - */ - query: z.string().optional().default(''), - /** - * Query language to use. - */ - language: z.enum(['kuery', 'lucene']).optional().default('kuery'), - }) -); +export type BaseCreateProps = z.infer; +export const BaseCreateProps = + BaseRequiredFields.and(BaseOptionalFields).and(BaseDefaultableFields); -export type SavedQueryRule = z.infer; -export const SavedQueryRule = BaseRule.and( - z.object({ - /** - * Rule type - */ - type: z.enum(['saved_query']), - index: z.array(z.string()).optional(), - data_view_id: z.string().optional(), - filters: z.array(z.unknown()).optional(), - saved_id: z.string(), - /** - * TODO - */ - response_actions: z.array(z.object({})).optional(), - alert_suppression: AlertSuppression.optional(), - /** - * Query to execute - */ - query: z.string().optional(), - /** - * Query language to use. - */ - language: z.enum(['kuery', 'lucene']).optional().default('kuery'), - }) -); +export type BasePatchProps = z.infer; +export const BasePatchProps = BaseRequiredFields.partial() + .and(BaseOptionalFields) + .and(BaseDefaultableFields); -export type ThresholdRule = z.infer; -export const ThresholdRule = BaseRule.and( - z.object({ - /** - * Rule type - */ - type: z.enum(['threshold']), - query: z.string(), - threshold: z.object({ - /** - * Field to aggregate on - */ - field: z.union([z.string(), z.array(z.string())]), - /** - * Threshold value - */ - value: z.number().int().min(1).optional(), - cardinality: z - .array( - z.object({ - field: z.string().optional(), - value: z.number().int().min(0).optional(), - }) - ) - .optional(), - }), - index: z.array(z.string()).optional(), - data_view_id: z.string().optional(), - filters: z.array(z.unknown()).optional(), - saved_id: z.string().optional(), - /** - * Query language to use. - */ - language: z.enum(['kuery', 'lucene']).optional().default('kuery'), - }) +export type BaseResponseProps = z.infer; +export const BaseResponseProps = BaseRequiredFields.and(BaseOptionalFields).and( + BaseDefaultableFields.required() ); -export type ThreatMatchRule = z.infer; -export const ThreatMatchRule = BaseRule.and( - z.object({ - /** - * Rule type - */ - type: z.enum(['threat_match']), - query: z.string(), - /** - * Query to execute - */ - threat_query: z.string(), - threat_mapping: z - .array( - z.object({ - entries: z - .array( - z.object({ - field: z.string().min(1).optional(), - type: z.enum(['mapping']).optional(), - value: z.string().min(1).optional(), - }) - ) - .optional(), - }) - ) - .min(1), - threat_index: z.array(z.string()), - index: z.array(z.string()).optional(), - data_view_id: z.string().optional(), - filters: z.array(z.unknown()).optional(), - saved_id: z.string().optional(), - threat_filters: z.array(z.unknown()).optional(), - /** - * Defines the path to the threat indicator in the indicator documents (optional) - */ - threat_indicator_path: z.string().optional(), - /** - * Query language to use. - */ - threat_language: z.enum(['kuery', 'lucene']).optional(), - concurrent_searches: z.number().int().min(1).optional(), - items_per_search: z.number().int().min(1).optional(), - /** - * Query language to use. - */ - language: z.enum(['kuery', 'lucene']).optional().default('kuery'), - }) -); +export type ResponseRequiredFields = z.infer; +export const ResponseRequiredFields = z.object({ + id: RuleObjectId, + rule_id: RuleSignatureId, + immutable: IsRuleImmutable, + updated_at: z.string().datetime(), + updated_by: z.string(), + created_at: z.string().datetime(), + created_by: z.string(), + revision: z.number().int().min(0), + related_integrations: RelatedIntegrationArray, + required_fields: RequiredFieldArray, + setup: SetupGuide, +}); -export type MlRule = z.infer; -export const MlRule = BaseRule.and( +export type ResponseOptionalFields = z.infer; +export const ResponseOptionalFields = z.object({ + execution_summary: RuleExecutionSummary.optional(), +}); + +export type SharedCreateProps = z.infer; +export const SharedCreateProps = BaseCreateProps.and( z.object({ - /** - * Rule type - */ - type: z.enum(['machine_learning']), - /** - * Anomaly threshold - */ - anomaly_threshold: z.number().int().min(0), - /** - * Machine learning job ID - */ - machine_learning_job_id: z.union([z.string(), z.array(z.string()).min(1)]), + rule_id: RuleSignatureId.optional(), }) ); -export type EqlRule = z.infer; -export const EqlRule = BaseRule.and( +export type SharedUpdateProps = z.infer; +export const SharedUpdateProps = BaseCreateProps.and( z.object({ - /** - * Rule type - */ - type: z.enum(['eql']), - language: z.enum(['eql']), - /** - * EQL query to execute - */ - query: z.string(), - index: z.array(z.string()).optional(), - data_view_id: z.string().optional(), - filters: z.array(z.unknown()).optional(), - /** - * Contains the event classification - */ - event_category_field: z.string().optional(), - /** - * Sets a secondary field for sorting events - */ - tiebreaker_field: z.string().optional(), - /** - * Contains the event timestamp used for sorting a sequence of events - */ - timestamp_field: z.string().optional(), + id: RuleObjectId.optional(), + rule_id: RuleSignatureId.optional(), }) ); -export type NewTermsRule = z.infer; -export const NewTermsRule = BaseRule.and( +export type SharedPatchProps = z.infer; +export const SharedPatchProps = BasePatchProps.and( z.object({ - /** - * Rule type - */ - type: z.enum(['new_terms']), - query: z.string(), - new_terms_fields: z.array(z.string()).min(1).max(3), - history_window_size: z.string().min(1).optional(), - index: z.array(z.string()).optional(), - data_view_id: z.string().optional(), - filters: z.array(z.unknown()).optional(), - language: z.enum(['kuery', 'lucene']).optional().default('kuery'), + id: RuleObjectId.optional(), + rule_id: RuleSignatureId.optional(), }) ); -export type Rule = z.infer; -export const Rule = z.union([ - QueryRule, - SavedQueryRule, - ThresholdRule, - ThreatMatchRule, - MlRule, - EqlRule, - NewTermsRule, -]); +export type SharedResponseProps = z.infer; +export const SharedResponseProps = + BaseResponseProps.and(ResponseRequiredFields).and(ResponseOptionalFields); -/** - * Defines the maximum interval in which a rule's actions are executed. - */ -export type Throttle = z.infer; -export const Throttle = z.enum(['rule', '1h', '1d', '7d']); -export const ThrottleEnum = Throttle.enum; -export type ThrottleEnum = typeof Throttle.enum; +export type EqlQueryLanguage = z.infer; +export const EqlQueryLanguage = z.literal('eql'); -export type Subtechnique = z.infer; -export const Subtechnique = z.object({ +export type EqlRequiredFields = z.infer; +export const EqlRequiredFields = z.object({ + /** + * Rule type + */ + type: z.literal('eql'), /** - * Subtechnique ID + * EQL query to execute */ - id: z.string(), + query: RuleQuery, + /** + * Query language to use + */ + language: EqlQueryLanguage, +}); + +export type EqlOptionalFields = z.infer; +export const EqlOptionalFields = z.object({ + index: IndexPatternArray.optional(), + data_view_id: DataViewId.optional(), + filters: RuleFilterArray.optional(), + event_category_override: EventCategoryOverride.optional(), + tiebreaker_field: TiebreakerField.optional(), + timestamp_field: TimestampField.optional(), +}); + +export type EqlRuleCreateFields = z.infer; +export const EqlRuleCreateFields = EqlRequiredFields.and(EqlOptionalFields); + +export type EqlRuleResponseFields = z.infer; +export const EqlRuleResponseFields = EqlRequiredFields.and(EqlOptionalFields); + +export type EqlRulePatchFields = z.infer; +export const EqlRulePatchFields = EqlRequiredFields.partial().and(EqlOptionalFields); + +export type EqlRule = z.infer; +export const EqlRule = SharedResponseProps.and(EqlRuleResponseFields); + +export type EqlRuleCreateProps = z.infer; +export const EqlRuleCreateProps = SharedCreateProps.and(EqlRuleCreateFields); + +export type EqlRuleUpdateProps = z.infer; +export const EqlRuleUpdateProps = SharedUpdateProps.and(EqlRuleCreateFields); + +export type EqlRulePatchProps = z.infer; +export const EqlRulePatchProps = SharedPatchProps.and(EqlRulePatchFields); + +export type QueryRuleRequiredFields = z.infer; +export const QueryRuleRequiredFields = z.object({ /** - * Subtechnique name + * Rule type */ - name: z.string(), + type: z.literal('query'), +}); + +export type QueryRuleOptionalFields = z.infer; +export const QueryRuleOptionalFields = z.object({ + index: IndexPatternArray.optional(), + data_view_id: DataViewId.optional(), + filters: RuleFilterArray.optional(), + saved_id: SavedQueryId.optional(), + response_actions: z.array(ResponseAction).optional(), + alert_suppression: AlertSuppression.optional(), +}); + +export type QueryRuleDefaultableFields = z.infer; +export const QueryRuleDefaultableFields = z.object({ + query: RuleQuery.optional(), + language: KqlQueryLanguage.optional(), +}); + +export type QueryRuleCreateFields = z.infer; +export const QueryRuleCreateFields = QueryRuleRequiredFields.and(QueryRuleOptionalFields).and( + QueryRuleDefaultableFields +); + +export type QueryRulePatchFields = z.infer; +export const QueryRulePatchFields = QueryRuleRequiredFields.partial() + .and(QueryRuleOptionalFields) + .and(QueryRuleDefaultableFields); + +export type QueryRuleResponseFields = z.infer; +export const QueryRuleResponseFields = QueryRuleRequiredFields.and(QueryRuleOptionalFields).and( + QueryRuleDefaultableFields.required() +); + +export type QueryRule = z.infer; +export const QueryRule = SharedResponseProps.and(QueryRuleResponseFields); + +export type QueryRuleCreateProps = z.infer; +export const QueryRuleCreateProps = SharedCreateProps.and(QueryRuleCreateFields); + +export type QueryRuleUpdateProps = z.infer; +export const QueryRuleUpdateProps = SharedUpdateProps.and(QueryRuleCreateFields); + +export type QueryRulePatchProps = z.infer; +export const QueryRulePatchProps = SharedPatchProps.and(QueryRulePatchFields); + +export type SavedQueryRuleRequiredFields = z.infer; +export const SavedQueryRuleRequiredFields = z.object({ /** - * Subtechnique reference + * Rule type */ - reference: z.string(), + type: z.literal('saved_query'), + saved_id: SavedQueryId, +}); + +export type SavedQueryRuleOptionalFields = z.infer; +export const SavedQueryRuleOptionalFields = z.object({ + index: IndexPatternArray.optional(), + data_view_id: DataViewId.optional(), + filters: RuleFilterArray.optional(), + response_actions: z.array(ResponseAction).optional(), + alert_suppression: AlertSuppression.optional(), + query: RuleQuery.optional(), +}); + +export type SavedQueryRuleDefaultableFields = z.infer; +export const SavedQueryRuleDefaultableFields = z.object({ + language: KqlQueryLanguage.optional(), }); -export type Technique = z.infer; -export const Technique = z.object({ +export type SavedQueryRuleCreateFields = z.infer; +export const SavedQueryRuleCreateFields = SavedQueryRuleRequiredFields.and( + SavedQueryRuleOptionalFields +).and(SavedQueryRuleDefaultableFields); + +export type SavedQueryRulePatchFields = z.infer; +export const SavedQueryRulePatchFields = SavedQueryRuleRequiredFields.partial() + .and(SavedQueryRuleOptionalFields) + .and(SavedQueryRuleDefaultableFields); + +export type SavedQueryRuleResponseFields = z.infer; +export const SavedQueryRuleResponseFields = SavedQueryRuleRequiredFields.and( + SavedQueryRuleOptionalFields +).and(SavedQueryRuleDefaultableFields.required()); + +export type SavedQueryRule = z.infer; +export const SavedQueryRule = SharedResponseProps.and(SavedQueryRuleResponseFields); + +export type SavedQueryRuleCreateProps = z.infer; +export const SavedQueryRuleCreateProps = SharedCreateProps.and(SavedQueryRuleCreateFields); + +export type SavedQueryRuleUpdateProps = z.infer; +export const SavedQueryRuleUpdateProps = SharedUpdateProps.and(SavedQueryRuleCreateFields); + +export type SavedQueryRulePatchProps = z.infer; +export const SavedQueryRulePatchProps = SharedPatchProps.and(SavedQueryRulePatchFields); + +export type ThresholdRuleRequiredFields = z.infer; +export const ThresholdRuleRequiredFields = z.object({ /** - * Technique ID + * Rule type */ - id: z.string(), + type: z.literal('threshold'), + query: RuleQuery, + threshold: Threshold, +}); + +export type ThresholdRuleOptionalFields = z.infer; +export const ThresholdRuleOptionalFields = z.object({ + index: IndexPatternArray.optional(), + data_view_id: DataViewId.optional(), + filters: RuleFilterArray.optional(), + saved_id: SavedQueryId.optional(), +}); + +export type ThresholdRuleDefaultableFields = z.infer; +export const ThresholdRuleDefaultableFields = z.object({ + language: KqlQueryLanguage.optional(), +}); + +export type ThresholdRuleCreateFields = z.infer; +export const ThresholdRuleCreateFields = ThresholdRuleRequiredFields.and( + ThresholdRuleOptionalFields +).and(ThresholdRuleDefaultableFields); + +export type ThresholdRulePatchFields = z.infer; +export const ThresholdRulePatchFields = ThresholdRuleRequiredFields.partial() + .and(ThresholdRuleOptionalFields) + .and(ThresholdRuleDefaultableFields); + +export type ThresholdRuleResponseFields = z.infer; +export const ThresholdRuleResponseFields = ThresholdRuleRequiredFields.and( + ThresholdRuleOptionalFields +).and(ThresholdRuleDefaultableFields.required()); + +export type ThresholdRule = z.infer; +export const ThresholdRule = SharedResponseProps.and(ThresholdRuleResponseFields); + +export type ThresholdRuleCreateProps = z.infer; +export const ThresholdRuleCreateProps = SharedCreateProps.and(ThresholdRuleCreateFields); + +export type ThresholdRuleUpdateProps = z.infer; +export const ThresholdRuleUpdateProps = SharedUpdateProps.and(ThresholdRuleCreateFields); + +export type ThresholdRulePatchProps = z.infer; +export const ThresholdRulePatchProps = SharedPatchProps.and(ThresholdRulePatchFields); + +export type ThreatMatchRuleRequiredFields = z.infer; +export const ThreatMatchRuleRequiredFields = z.object({ /** - * Technique name + * Rule type */ - name: z.string(), + type: z.literal('threat_match'), + query: RuleQuery, + threat_query: ThreatQuery, + threat_mapping: ThreatMapping, + threat_index: ThreatIndex, +}); + +export type ThreatMatchRuleOptionalFields = z.infer; +export const ThreatMatchRuleOptionalFields = z.object({ + index: IndexPatternArray.optional(), + data_view_id: DataViewId.optional(), + filters: RuleFilterArray.optional(), + saved_id: SavedQueryId.optional(), + threat_filters: ThreatFilters.optional(), + threat_indicator_path: ThreatIndicatorPath.optional(), + threat_language: KqlQueryLanguage.optional(), + concurrent_searches: ConcurrentSearches.optional(), + items_per_search: ItemsPerSearch.optional(), +}); + +export type ThreatMatchRuleDefaultableFields = z.infer; +export const ThreatMatchRuleDefaultableFields = z.object({ + language: KqlQueryLanguage.optional(), +}); + +export type ThreatMatchRuleCreateFields = z.infer; +export const ThreatMatchRuleCreateFields = ThreatMatchRuleRequiredFields.and( + ThreatMatchRuleOptionalFields +).and(ThreatMatchRuleDefaultableFields); + +export type ThreatMatchRulePatchFields = z.infer; +export const ThreatMatchRulePatchFields = ThreatMatchRuleRequiredFields.partial() + .and(ThreatMatchRuleOptionalFields) + .and(ThreatMatchRuleDefaultableFields); + +export type ThreatMatchRuleResponseFields = z.infer; +export const ThreatMatchRuleResponseFields = ThreatMatchRuleRequiredFields.and( + ThreatMatchRuleOptionalFields +).and(ThreatMatchRuleDefaultableFields.required()); + +export type ThreatMatchRule = z.infer; +export const ThreatMatchRule = SharedResponseProps.and(ThreatMatchRuleResponseFields); + +export type ThreatMatchRuleCreateProps = z.infer; +export const ThreatMatchRuleCreateProps = SharedCreateProps.and(ThreatMatchRuleCreateFields); + +export type ThreatMatchRuleUpdateProps = z.infer; +export const ThreatMatchRuleUpdateProps = SharedUpdateProps.and(ThreatMatchRuleCreateFields); + +export type ThreatMatchRulePatchProps = z.infer; +export const ThreatMatchRulePatchProps = SharedPatchProps.and(ThreatMatchRulePatchFields); + +export type MachineLearningRuleRequiredFields = z.infer; +export const MachineLearningRuleRequiredFields = z.object({ /** - * Technique reference + * Rule type */ - reference: z.string(), + type: z.literal('machine_learning'), + anomaly_threshold: AnomalyThreshold, + machine_learning_job_id: MachineLearningJobId, +}); + +export type MachineLearningRulePatchFields = z.infer; +export const MachineLearningRulePatchFields = MachineLearningRuleRequiredFields.partial(); + +export type MachineLearningRuleResponseFields = z.infer; +export const MachineLearningRuleResponseFields = MachineLearningRuleRequiredFields; + +export type MachineLearningRuleCreateFields = z.infer; +export const MachineLearningRuleCreateFields = MachineLearningRuleRequiredFields; + +export type MachineLearningRule = z.infer; +export const MachineLearningRule = SharedResponseProps.and(MachineLearningRuleResponseFields); + +export type MachineLearningRuleCreateProps = z.infer; +export const MachineLearningRuleCreateProps = SharedCreateProps.and( + MachineLearningRuleCreateFields +); + +export type MachineLearningRuleUpdateProps = z.infer; +export const MachineLearningRuleUpdateProps = SharedUpdateProps.and( + MachineLearningRuleCreateFields +); + +export type MachineLearningRulePatchProps = z.infer; +export const MachineLearningRulePatchProps = SharedPatchProps.and(MachineLearningRulePatchFields); + +export type NewTermsRuleRequiredFields = z.infer; +export const NewTermsRuleRequiredFields = z.object({ /** - * Array containing more specific information on the attack technique + * Rule type */ - subtechnique: z.array(Subtechnique).optional(), + type: z.literal('new_terms'), + query: RuleQuery, + new_terms_fields: NewTermsFields, + history_window_start: HistoryWindowStart, +}); + +export type NewTermsRuleOptionalFields = z.infer; +export const NewTermsRuleOptionalFields = z.object({ + index: IndexPatternArray.optional(), + data_view_id: DataViewId.optional(), + filters: RuleFilterArray.optional(), }); -export type Threat = z.infer; -export const Threat = z.object({ +export type NewTermsRuleDefaultableFields = z.infer; +export const NewTermsRuleDefaultableFields = z.object({ + language: KqlQueryLanguage.optional(), +}); + +export type NewTermsRulePatchFields = z.infer; +export const NewTermsRulePatchFields = NewTermsRuleRequiredFields.partial() + .and(NewTermsRuleOptionalFields) + .and(NewTermsRuleDefaultableFields); + +export type NewTermsRuleResponseFields = z.infer; +export const NewTermsRuleResponseFields = NewTermsRuleRequiredFields.and( + NewTermsRuleOptionalFields +).and(NewTermsRuleDefaultableFields.required()); + +export type NewTermsRuleCreateFields = z.infer; +export const NewTermsRuleCreateFields = NewTermsRuleRequiredFields.and( + NewTermsRuleOptionalFields +).and(NewTermsRuleDefaultableFields); + +export type NewTermsRule = z.infer; +export const NewTermsRule = SharedResponseProps.and(NewTermsRuleResponseFields); + +export type NewTermsRuleCreateProps = z.infer; +export const NewTermsRuleCreateProps = SharedCreateProps.and(NewTermsRuleCreateFields); + +export type NewTermsRuleUpdateProps = z.infer; +export const NewTermsRuleUpdateProps = SharedUpdateProps.and(NewTermsRuleCreateFields); + +export type NewTermsRulePatchProps = z.infer; +export const NewTermsRulePatchProps = SharedPatchProps.and(NewTermsRulePatchFields); + +export type EsqlQueryLanguage = z.infer; +export const EsqlQueryLanguage = z.literal('esql'); + +export type EsqlRuleRequiredFields = z.infer; +export const EsqlRuleRequiredFields = z.object({ /** - * Relevant attack framework + * Rule type */ - framework: z.string(), - tactic: z.object({ - /** - * Tactic ID - */ - id: z.string(), - /** - * Tactic name - */ - name: z.string(), - /** - * Tactic reference - */ - reference: z.string(), - }), + type: z.literal('esql'), + language: EsqlQueryLanguage, /** - * Array containing information on the attack techniques (optional) + * ESQL query to execute */ - technique: z.array(Technique).optional(), + query: RuleQuery, }); -export type RuleResponse = z.infer; -export const RuleResponse = z.object({}); +export type EsqlRulePatchFields = z.infer; +export const EsqlRulePatchFields = EsqlRuleRequiredFields.partial(); + +export type EsqlRuleResponseFields = z.infer; +export const EsqlRuleResponseFields = EsqlRuleRequiredFields; + +export type EsqlRuleCreateFields = z.infer; +export const EsqlRuleCreateFields = EsqlRuleRequiredFields; + +export type EsqlRule = z.infer; +export const EsqlRule = SharedResponseProps.and(EsqlRuleResponseFields); + +export type EsqlRuleCreateProps = z.infer; +export const EsqlRuleCreateProps = SharedCreateProps.and(EsqlRuleCreateFields); + +export type EsqlRuleUpdateProps = z.infer; +export const EsqlRuleUpdateProps = SharedUpdateProps.and(EsqlRuleCreateFields); + +export type EsqlRulePatchProps = z.infer; +export const EsqlRulePatchProps = SharedPatchProps.and(EsqlRulePatchFields.partial()); + +export type TypeSpecificCreateProps = z.infer; +export const TypeSpecificCreateProps = z.union([ + EqlRuleCreateFields, + QueryRuleCreateFields, + SavedQueryRuleCreateFields, + ThresholdRuleCreateFields, + ThreatMatchRuleCreateFields, + MachineLearningRuleCreateFields, + NewTermsRuleCreateFields, + EsqlRuleCreateFields, +]); + +export type TypeSpecificPatchProps = z.infer; +export const TypeSpecificPatchProps = z.union([ + EqlRulePatchFields, + QueryRulePatchFields, + SavedQueryRulePatchFields, + ThresholdRulePatchFields, + ThreatMatchRulePatchFields, + MachineLearningRulePatchFields, + NewTermsRulePatchFields, + EsqlRulePatchFields, +]); + +export type TypeSpecificResponse = z.infer; +export const TypeSpecificResponse = z.union([ + EqlRuleResponseFields, + QueryRuleResponseFields, + SavedQueryRuleResponseFields, + ThresholdRuleResponseFields, + ThreatMatchRuleResponseFields, + MachineLearningRuleResponseFields, + NewTermsRuleResponseFields, + EsqlRuleResponseFields, +]); export type RuleCreateProps = z.infer; -export const RuleCreateProps = z.object({}); +export const RuleCreateProps = z.union([ + EqlRuleCreateProps, + QueryRuleCreateProps, + SavedQueryRuleCreateProps, + ThresholdRuleCreateProps, + ThreatMatchRuleCreateProps, + MachineLearningRuleCreateProps, + NewTermsRuleCreateProps, + EsqlRuleCreateProps, +]); export type RuleUpdateProps = z.infer; -export const RuleUpdateProps = z.object({}); +export const RuleUpdateProps = z.union([ + EqlRuleUpdateProps, + QueryRuleUpdateProps, + SavedQueryRuleUpdateProps, + ThresholdRuleUpdateProps, + ThreatMatchRuleUpdateProps, + MachineLearningRuleUpdateProps, + NewTermsRuleUpdateProps, + EsqlRuleUpdateProps, +]); export type RulePatchProps = z.infer; -export const RulePatchProps = z.object({}); +export const RulePatchProps = z.union([ + EqlRulePatchProps, + QueryRulePatchProps, + SavedQueryRulePatchProps, + ThresholdRulePatchProps, + ThreatMatchRulePatchProps, + MachineLearningRulePatchProps, + NewTermsRulePatchProps, + EsqlRulePatchProps, +]); + +export type RuleResponse = z.infer; +export const RuleResponse = z.union([ + EqlRule, + QueryRule, + SavedQueryRule, + ThresholdRule, + ThreatMatchRule, + MachineLearningRule, + NewTermsRule, + EsqlRule, +]); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml index 16cc2aec5cf2ba..955916b939e82b 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.schema.yaml @@ -6,754 +6,913 @@ paths: {} components: x-codegen-enabled: true schemas: - Action: - type: object - properties: - action_type_id: - type: string - description: The action type used for sending notifications. - group: - type: string - description: Optionally groups actions by use cases. Use `default` for alert notifications. - id: - type: string - description: The connector ID. - params: - type: object - description: Object containing the allowed connector fields, which varies according to the connector type. - uuid: - type: string - alerts_filter: - type: object - description: TODO implement the schema type - frequency: - type: object - description: TODO implement the schema type - required: - - action_type_id - - group - - id - - params - - AlertSuppression: - type: object - properties: - group_by: - type: array - items: - type: string - minItems: 1 - maxItems: 3 - duration: - type: object - properties: - value: - type: integer - minimum: 1 - unit: - type: string - enum: - - s - - m - - h - required: - - value - - unit - missing_fields_strategy: - type: string - enum: - - doNotSuppress - - suppress - required: - - group_by - - BaseRule: + BaseRequiredFields: type: object properties: name: - type: string - description: Rule name + $ref: './common_attributes.schema.yaml#/components/schemas/RuleName' description: - type: string - description: Rule description + $ref: './common_attributes.schema.yaml#/components/schemas/RuleDescription' risk_score: - type: integer - description: Risk score (0 to 100) - minimum: 0 - maximum: 100 + $ref: './common_attributes.schema.yaml#/components/schemas/RiskScore' severity: - type: string - enum: [low, medium, high, critical] - description: Severity of the rule + $ref: './common_attributes.schema.yaml#/components/schemas/Severity' + required: + - name + - description + - risk_score + - severity + + BaseOptionalFields: + type: object + properties: + # Field overrides rule_name_override: - type: string - description: Sets the source field for the alert's signal.rule.name value + $ref: './common_attributes.schema.yaml#/components/schemas/RuleNameOverride' + timestamp_override: - type: string - description: Sets the time field used to query indices (optional) + $ref: './common_attributes.schema.yaml#/components/schemas/TimestampOverride' + + timestamp_override_fallback_disabled: + $ref: './common_attributes.schema.yaml#/components/schemas/TimestampOverrideFallbackDisabled' + + # Timeline template timeline_id: - type: string - description: Timeline template ID + $ref: './common_attributes.schema.yaml#/components/schemas/TimelineTemplateId' + timeline_title: - type: string - description: Timeline template title + $ref: './common_attributes.schema.yaml#/components/schemas/TimelineTemplateTitle' + + # Attributes related to SavedObjectsClient.resolve API outcome: - type: string - enum: - - exactMatch - - aliasMatch - - conflict + $ref: './common_attributes.schema.yaml#/components/schemas/SavedObjectResolveOutcome' alias_target_id: - type: string - description: TODO + $ref: './common_attributes.schema.yaml#/components/schemas/SavedObjectResolveAliasTargetId' alias_purpose: - type: string - enum: - - savedObjectConversion - - savedObjectImport - description: TODO + $ref: './common_attributes.schema.yaml#/components/schemas/SavedObjectResolveAliasPurpose' + + # Misc attributes license: - type: string - description: The rule’s license. + $ref: './common_attributes.schema.yaml#/components/schemas/RuleLicense' note: - type: string - description: Notes to help investigate alerts produced by the rule. + $ref: './common_attributes.schema.yaml#/components/schemas/InvestigationGuide' building_block_type: - type: string - description: Determines if the rule acts as a building block. By default, building-block alerts are not displayed in the UI. These rules are used as a foundation for other rules that do generate alerts. Its value must be default. + $ref: './common_attributes.schema.yaml#/components/schemas/BuildingBlockType' + output_index: - type: string - description: (deprecated) Has no effect. + $ref: './common_attributes.schema.yaml#/components/schemas/AlertsIndex' namespace: - type: string - description: Has no effect. + $ref: './common_attributes.schema.yaml#/components/schemas/AlertsIndexNamespace' meta: - type: object - description: Stores rule metadata. + $ref: './common_attributes.schema.yaml#/components/schemas/RuleMetadata' + investigation_fields: + $ref: './common_attributes.schema.yaml#/components/schemas/InvestigationFields' + + # Throttle throttle: - type: string - description: Defines the interval on which a rule's actions are executed. + $ref: './common_attributes.schema.yaml#/components/schemas/RuleActionThrottle' + + BaseDefaultableFields: + type: object + properties: + # Main attributes version: - type: integer - minimum: 1 - default: 1 - description: The rule’s version number. Defaults to 1. + $ref: './common_attributes.schema.yaml#/components/schemas/RuleVersion' tags: - type: array - items: - type: string - default: [] - description: String array containing words and phrases to help categorize, filter, and search rules. Defaults to an empty array. + $ref: './common_attributes.schema.yaml#/components/schemas/RuleTagArray' enabled: - type: boolean - default: true - description: Determines whether the rule is enabled. Defaults to true. + $ref: './common_attributes.schema.yaml#/components/schemas/IsRuleEnabled' + + # Field overrides risk_score_mapping: - type: array - items: - type: object - properties: - field: - type: string - operator: - type: string - enum: - - equals - value: - type: string - risk_score: - type: integer - minimum: 0 - maximum: 100 - required: - - field - - value - - operator - description: Overrides generated alerts' risk_score with a value from the source event - default: [] + $ref: './common_attributes.schema.yaml#/components/schemas/RiskScoreMapping' + severity_mapping: - type: array - items: - type: object - properties: - field: - type: string - operator: - type: string - enum: - - equals - severity: - type: string - enum: - - low - - medium - - high - - critical - value: - type: string - required: - - field - - operator - - severity - - value - description: Overrides generated alerts' severity with values from the source event - default: [] + $ref: './common_attributes.schema.yaml#/components/schemas/SeverityMapping' + + # Rule schedule interval: - type: string - description: Frequency of rule execution, using a date math range. For example, "1h" means the rule runs every hour. Defaults to 5m (5 minutes). - default: 5m + $ref: './common_attributes.schema.yaml#/components/schemas/RuleInterval' from: - type: string - description: Time from which data is analyzed each time the rule executes, using a date math range. For example, now-4200s means the rule analyzes data from 70 minutes before its start time. Defaults to now-6m (analyzes data from 6 minutes before the start time). - default: now-6m + $ref: './common_attributes.schema.yaml#/components/schemas/RuleIntervalFrom' to: - type: string - description: TODO - default: now + $ref: './common_attributes.schema.yaml#/components/schemas/RuleIntervalTo' + + # Rule actions actions: type: array items: - $ref: '#/components/schemas/Action' - default: [] + $ref: './common_attributes.schema.yaml#/components/schemas/RuleAction' + + # Rule exceptions exceptions_list: type: array items: - type: object - properties: - id: - type: string - description: ID of the exception container - minLength: 1 - list_id: - type: string - description: List ID of the exception container - minLength: 1 - type: - type: string - description: The exception type - enum: - - detection - - rule_default - - endpoint - - endpoint_trusted_apps - - endpoint_events - - endpoint_host_isolation_exceptions - - endpoint_blocklists - namespace_type: - type: string - description: Determines the exceptions validity in rule's Kibana space - enum: - - agnostic - - single - required: - - id - - list_id - - type - - namespace_type - default: [] + $ref: './common_attributes.schema.yaml#/components/schemas/RuleExceptionList' + + # Misc attributes author: - type: array - items: - type: string - default: [] + $ref: './common_attributes.schema.yaml#/components/schemas/RuleAuthorArray' + false_positives: - type: array - items: - type: string - default: [] + $ref: './common_attributes.schema.yaml#/components/schemas/RuleFalsePositiveArray' + references: - type: array - items: - type: string - default: [] + $ref: './common_attributes.schema.yaml#/components/schemas/RuleReferenceArray' + + # maxSignals not used in ML rules but probably should be used max_signals: - type: integer - minimum: 1 - default: 100 + $ref: './common_attributes.schema.yaml#/components/schemas/MaxSignals' threat: - type: array - items: - type: object - properties: - framework: - type: string - description: Relevant attack framework - tactic: - type: object - properties: - id: - type: string - name: - type: string - reference: - type: string - required: - - id - - name - - reference - technique: - type: array - items: - type: object - properties: - id: - type: string - name: - type: string - reference: - type: string - subtechnique: - type: array - items: - type: object - properties: - id: - type: string - name: - type: string - reference: - type: string - required: - - id - - name - - reference - required: - - id - - name - - reference - required: - - framework - - tactic - required: - - id - - name - - description - - risk_score - - severity + $ref: './common_attributes.schema.yaml#/components/schemas/ThreatArray' - QueryRule: + BaseCreateProps: allOf: - - $ref: '#/components/schemas/BaseRule' - - type: object - properties: - type: - type: string - enum: [query] - description: Rule type - index: - type: array - items: - type: string - data_view_id: - type: string - filters: - type: array - items: {} # unknown - saved_id: - type: string - response_actions: - type: array - items: - type: object - description: TODO - alert_suppression: - $ref: '#/components/schemas/AlertSuppression' - query: - type: string - description: Query to execute - default: '' - language: - type: string - enum: - - kuery - - lucene - default: kuery - description: Query language to use. - required: - - type + - $ref: '#/components/schemas/BaseRequiredFields' + - $ref: '#/components/schemas/BaseOptionalFields' + - $ref: '#/components/schemas/BaseDefaultableFields' - SavedQueryRule: + BasePatchProps: allOf: - - $ref: '#/components/schemas/BaseRule' - - type: object - properties: - type: - type: string - enum: [saved_query] - description: Rule type - index: - type: array - items: - type: string - data_view_id: - type: string - filters: - type: array - items: {} # unknown - saved_id: - type: string - response_actions: - type: array - items: - type: object - description: TODO - alert_suppression: - $ref: '#/components/schemas/AlertSuppression' - query: - type: string - description: Query to execute - language: - type: string - enum: - - kuery - - lucene - default: kuery - description: Query language to use. - required: - - type - - saved_id + - $ref: '#/components/schemas/BaseRequiredFields' + x-modify: partial + - $ref: '#/components/schemas/BaseOptionalFields' + - $ref: '#/components/schemas/BaseDefaultableFields' - ThresholdRule: + BaseResponseProps: allOf: - - $ref: '#/components/schemas/BaseRule' - - type: object - properties: - type: - type: string - enum: [threshold] - description: Rule type - query: - type: string - threshold: - type: object - properties: - field: - oneOf: - - type: string - - type: array - items: - type: string - description: Field to aggregate on - value: - type: integer - minimum: 1 - description: Threshold value - cardinality: - type: array - items: - type: object - properties: - field: - type: string - value: - type: integer - minimum: 0 - index: - type: array - items: - type: string - data_view_id: - type: string - filters: - type: array - items: {} # unknown - saved_id: - type: string - language: - type: string - enum: - - kuery - - lucene - default: kuery - description: Query language to use. - required: - - type - - query - - threshold - ThreatMatchRule: + - $ref: '#/components/schemas/BaseRequiredFields' + - $ref: '#/components/schemas/BaseOptionalFields' + - $ref: '#/components/schemas/BaseDefaultableFields' + x-modify: required + + ResponseRequiredFields: + type: object + properties: + id: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleObjectId' + rule_id: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleSignatureId' + immutable: + $ref: './common_attributes.schema.yaml#/components/schemas/IsRuleImmutable' + updated_at: + type: string + format: date-time + updated_by: + type: string + created_at: + type: string + format: date-time + created_by: + type: string + revision: + type: integer + minimum: 0 + # NOTE: For now, Related Integrations, Required Fields and Setup Guide are + # supported for prebuilt rules only. We don't want to allow users to edit these 3 + # fields via the API. If we added them to baseParams.defaultable, they would + # become a part of the request schema as optional fields. This is why we add them + # here, in order to add them only to the response schema. + related_integrations: + $ref: './common_attributes.schema.yaml#/components/schemas/RelatedIntegrationArray' + required_fields: + $ref: './common_attributes.schema.yaml#/components/schemas/RequiredFieldArray' + setup: + $ref: './common_attributes.schema.yaml#/components/schemas/SetupGuide' + required: + - id + - rule_id + - immutable + - updated_at + - updated_by + - created_at + - created_by + - revision + - related_integrations + - required_fields + - setup + + ResponseOptionalFields: + type: object + properties: + execution_summary: + $ref: '../../rule_monitoring/model/execution_summary.schema.yaml#/components/schemas/RuleExecutionSummary' + + SharedCreateProps: allOf: - - $ref: '#/components/schemas/BaseRule' + - $ref: '#/components/schemas/BaseCreateProps' - type: object properties: - type: - type: string - enum: [threat_match] - description: Rule type - query: - type: string - threat_query: - type: string - description: Query to execute - threat_mapping: - type: array - minItems: 1 - items: - type: object - properties: - entries: - type: array - items: - type: object - properties: - field: - type: string - minLength: 1 - type: - type: string - enum: - - mapping - value: - type: string - minLength: 1 - threat_index: - type: array - items: - type: string - index: - type: array - items: - type: string - data_view_id: - type: string - filters: - type: array - items: {} # unknown - saved_id: - type: string - threat_filters: - type: array - items: - description: Query and filter context array used to filter documents from the Elasticsearch index containing the threat values - threat_indicator_path: - type: string - description: Defines the path to the threat indicator in the indicator documents (optional) - threat_language: - type: string - enum: - - kuery - - lucene - description: Query language to use. - concurrent_searches: - type: integer - minimum: 1 - items_per_search: - type: integer - minimum: 1 - language: - type: string - enum: - - kuery - - lucene - default: kuery - description: Query language to use. - required: - - type - - query - - threat_query - - threat_mapping - - threat_index - MlRule: - allOf: - - $ref: '#/components/schemas/BaseRule' - - type: object - properties: - type: - type: string - enum: [machine_learning] - description: Rule type - anomaly_threshold: - type: integer - minimum: 0 - description: Anomaly threshold - machine_learning_job_id: - oneOf: - - type: string - - type: array - items: - type: string - minItems: 1 - description: Machine learning job ID - required: - - type - - machine_learning_job_id - - anomaly_threshold - EqlRule: + rule_id: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleSignatureId' + + SharedUpdateProps: allOf: - - $ref: '#/components/schemas/BaseRule' + - $ref: '#/components/schemas/BaseCreateProps' - type: object properties: - type: - type: string - enum: [eql] - description: Rule type - language: - type: string - enum: - - eql - query: - type: string - description: EQL query to execute - index: - type: array - items: - type: string - data_view_id: - type: string - filters: - type: array - items: {} # unknown - event_category_field: - type: string - description: Contains the event classification - tiebreaker_field: - type: string - description: Sets a secondary field for sorting events - timestamp_field: - type: string - description: Contains the event timestamp used for sorting a sequence of events - required: - - type - - language - - query + id: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleObjectId' + rule_id: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleSignatureId' - NewTermsRule: + SharedPatchProps: allOf: - - $ref: '#/components/schemas/BaseRule' + - $ref: '#/components/schemas/BasePatchProps' - type: object properties: - type: - type: string - enum: [new_terms] - description: Rule type - query: - type: string - new_terms_fields: - type: array - items: - type: string - minItems: 1 - maxItems: 3 - history_window_size: - type: string - minLength: 1 - index: - type: array - items: - type: string - data_view_id: - type: string - filters: - type: array - items: {} # unknown - language: - type: string - enum: - - kuery - - lucene - default: kuery - required: - - type - - query - - new_terms_fields - - history_window_start - - Rule: - oneOf: - - $ref: '#/components/schemas/QueryRule' - - $ref: '#/components/schemas/SavedQueryRule' - - $ref: '#/components/schemas/ThresholdRule' - - $ref: '#/components/schemas/ThreatMatchRule' - - $ref: '#/components/schemas/MlRule' - - $ref: '#/components/schemas/EqlRule' - - $ref: '#/components/schemas/NewTermsRule' + id: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleObjectId' + rule_id: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleSignatureId' + + SharedResponseProps: + allOf: + - $ref: '#/components/schemas/BaseResponseProps' + - $ref: '#/components/schemas/ResponseRequiredFields' + - $ref: '#/components/schemas/ResponseOptionalFields' - Throttle: + ############ + # EQL Rule # + ############ + + EqlQueryLanguage: type: string - description: Defines the maximum interval in which a rule's actions are executed. enum: - - rule - - 1h - - 1d - - 7d + - eql - Subtechnique: + EqlRequiredFields: type: object properties: - id: + type: type: string - description: Subtechnique ID - name: + enum: [eql] + description: Rule type + query: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' + description: EQL query to execute + language: + $ref: '#/components/schemas/EqlQueryLanguage' + description: Query language to use + required: + - type + - query + - language + + EqlOptionalFields: + type: object + properties: + index: + $ref: './common_attributes.schema.yaml#/components/schemas/IndexPatternArray' + data_view_id: + $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' + filters: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' + event_category_override: + $ref: './specific_attributes/eql_attributes.schema.yaml#/components/schemas/EventCategoryOverride' + tiebreaker_field: + $ref: './specific_attributes/eql_attributes.schema.yaml#/components/schemas/TiebreakerField' + timestamp_field: + $ref: './specific_attributes/eql_attributes.schema.yaml#/components/schemas/TimestampField' + + EqlRuleCreateFields: + allOf: + - $ref: '#/components/schemas/EqlRequiredFields' + - $ref: '#/components/schemas/EqlOptionalFields' + + EqlRuleResponseFields: + allOf: + - $ref: '#/components/schemas/EqlRequiredFields' + - $ref: '#/components/schemas/EqlOptionalFields' + + EqlRulePatchFields: + allOf: + - $ref: '#/components/schemas/EqlRequiredFields' + x-modify: partial + - $ref: '#/components/schemas/EqlOptionalFields' + + EqlRule: + allOf: + - $ref: '#/components/schemas/SharedResponseProps' + - $ref: '#/components/schemas/EqlRuleResponseFields' + + EqlRuleCreateProps: + allOf: + - $ref: '#/components/schemas/SharedCreateProps' + - $ref: '#/components/schemas/EqlRuleCreateFields' + + EqlRuleUpdateProps: + allOf: + - $ref: '#/components/schemas/SharedUpdateProps' + - $ref: '#/components/schemas/EqlRuleCreateFields' + + EqlRulePatchProps: + allOf: + - $ref: '#/components/schemas/SharedPatchProps' + - $ref: '#/components/schemas/EqlRulePatchFields' + + ############## + # Query Rule # + ############## + + QueryRuleRequiredFields: + type: object + properties: + type: type: string - description: Subtechnique name - reference: + enum: [query] + description: Rule type + required: + - type + + QueryRuleOptionalFields: + type: object + properties: + index: + $ref: './common_attributes.schema.yaml#/components/schemas/IndexPatternArray' + data_view_id: + $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' + filters: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' + saved_id: + $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' + alert_suppression: + $ref: './specific_attributes/query_attributes.schema.yaml#/components/schemas/AlertSuppression' + + QueryRuleDefaultableFields: + type: object + properties: + query: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' + language: + $ref: './common_attributes.schema.yaml#/components/schemas/KqlQueryLanguage' + + QueryRuleCreateFields: + allOf: + - $ref: '#/components/schemas/QueryRuleRequiredFields' + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - $ref: '#/components/schemas/QueryRuleDefaultableFields' + + QueryRulePatchFields: + allOf: + - $ref: '#/components/schemas/QueryRuleRequiredFields' + x-modify: partial + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - $ref: '#/components/schemas/QueryRuleDefaultableFields' + + QueryRuleResponseFields: + allOf: + - $ref: '#/components/schemas/QueryRuleRequiredFields' + - $ref: '#/components/schemas/QueryRuleOptionalFields' + - $ref: '#/components/schemas/QueryRuleDefaultableFields' + x-modify: required + + QueryRule: + allOf: + - $ref: '#/components/schemas/SharedResponseProps' + - $ref: '#/components/schemas/QueryRuleResponseFields' + + QueryRuleCreateProps: + allOf: + - $ref: '#/components/schemas/SharedCreateProps' + - $ref: '#/components/schemas/QueryRuleCreateFields' + + QueryRuleUpdateProps: + allOf: + - $ref: '#/components/schemas/SharedUpdateProps' + - $ref: '#/components/schemas/QueryRuleCreateFields' + + QueryRulePatchProps: + allOf: + - $ref: '#/components/schemas/SharedPatchProps' + - $ref: '#/components/schemas/QueryRulePatchFields' + + #################### + # Saved Query Rule # + #################### + + SavedQueryRuleRequiredFields: + type: object + properties: + type: type: string - description: Subtechnique reference + enum: [saved_query] + description: Rule type + saved_id: + $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' required: - - id - - name - - reference + - type + - saved_id - Technique: + SavedQueryRuleOptionalFields: type: object properties: - id: + index: + $ref: './common_attributes.schema.yaml#/components/schemas/IndexPatternArray' + data_view_id: + $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' + filters: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' + response_actions: + type: array + items: + $ref: '../rule_response_actions/response_actions.schema.yaml#/components/schemas/ResponseAction' + alert_suppression: + $ref: './specific_attributes/query_attributes.schema.yaml#/components/schemas/AlertSuppression' + query: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' + + SavedQueryRuleDefaultableFields: + type: object + properties: + language: + $ref: './common_attributes.schema.yaml#/components/schemas/KqlQueryLanguage' + + SavedQueryRuleCreateFields: + allOf: + - $ref: '#/components/schemas/SavedQueryRuleRequiredFields' + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - $ref: '#/components/schemas/SavedQueryRuleDefaultableFields' + + SavedQueryRulePatchFields: + allOf: + - $ref: '#/components/schemas/SavedQueryRuleRequiredFields' + x-modify: partial + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - $ref: '#/components/schemas/SavedQueryRuleDefaultableFields' + + SavedQueryRuleResponseFields: + allOf: + - $ref: '#/components/schemas/SavedQueryRuleRequiredFields' + - $ref: '#/components/schemas/SavedQueryRuleOptionalFields' + - $ref: '#/components/schemas/SavedQueryRuleDefaultableFields' + x-modify: required + + SavedQueryRule: + allOf: + - $ref: '#/components/schemas/SharedResponseProps' + - $ref: '#/components/schemas/SavedQueryRuleResponseFields' + + SavedQueryRuleCreateProps: + allOf: + - $ref: '#/components/schemas/SharedCreateProps' + - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + + SavedQueryRuleUpdateProps: + allOf: + - $ref: '#/components/schemas/SharedUpdateProps' + - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + + SavedQueryRulePatchProps: + allOf: + - $ref: '#/components/schemas/SharedPatchProps' + - $ref: '#/components/schemas/SavedQueryRulePatchFields' + + ################## + # Threshold Rule # + ################## + + ThresholdRuleRequiredFields: + type: object + properties: + type: type: string - description: Technique ID - name: + enum: [threshold] + description: Rule type + query: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' + threshold: + $ref: './specific_attributes/threshold_attributes.schema.yaml#/components/schemas/Threshold' + required: + - type + - query + - threshold + + ThresholdRuleOptionalFields: + type: object + properties: + index: + $ref: './common_attributes.schema.yaml#/components/schemas/IndexPatternArray' + data_view_id: + $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' + filters: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' + saved_id: + $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' + + ThresholdRuleDefaultableFields: + type: object + properties: + language: + $ref: './common_attributes.schema.yaml#/components/schemas/KqlQueryLanguage' + + ThresholdRuleCreateFields: + allOf: + - $ref: '#/components/schemas/ThresholdRuleRequiredFields' + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - $ref: '#/components/schemas/ThresholdRuleDefaultableFields' + + ThresholdRulePatchFields: + allOf: + - $ref: '#/components/schemas/ThresholdRuleRequiredFields' + x-modify: partial + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - $ref: '#/components/schemas/ThresholdRuleDefaultableFields' + + ThresholdRuleResponseFields: + allOf: + - $ref: '#/components/schemas/ThresholdRuleRequiredFields' + - $ref: '#/components/schemas/ThresholdRuleOptionalFields' + - $ref: '#/components/schemas/ThresholdRuleDefaultableFields' + x-modify: required + + ThresholdRule: + allOf: + - $ref: '#/components/schemas/SharedResponseProps' + - $ref: '#/components/schemas/ThresholdRuleResponseFields' + + ThresholdRuleCreateProps: + allOf: + - $ref: '#/components/schemas/SharedCreateProps' + - $ref: '#/components/schemas/ThresholdRuleCreateFields' + + ThresholdRuleUpdateProps: + allOf: + - $ref: '#/components/schemas/SharedUpdateProps' + - $ref: '#/components/schemas/ThresholdRuleCreateFields' + + ThresholdRulePatchProps: + allOf: + - $ref: '#/components/schemas/SharedPatchProps' + - $ref: '#/components/schemas/ThresholdRulePatchFields' + + ##################### + # Threat Match Rule # + ##################### + + ThreatMatchRuleRequiredFields: + type: object + properties: + type: type: string - description: Technique name - reference: + enum: [threat_match] + description: Rule type + query: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' + threat_query: + $ref: './specific_attributes/threat_match_attributes.schema.yaml#/components/schemas/ThreatQuery' + threat_mapping: + $ref: './specific_attributes/threat_match_attributes.schema.yaml#/components/schemas/ThreatMapping' + threat_index: + $ref: './specific_attributes/threat_match_attributes.schema.yaml#/components/schemas/ThreatIndex' + required: + - type + - query + - threat_query + - threat_mapping + - threat_index + + ThreatMatchRuleOptionalFields: + type: object + properties: + index: + $ref: './common_attributes.schema.yaml#/components/schemas/IndexPatternArray' + data_view_id: + $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' + filters: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' + saved_id: + $ref: './common_attributes.schema.yaml#/components/schemas/SavedQueryId' + threat_filters: + $ref: './specific_attributes/threat_match_attributes.schema.yaml#/components/schemas/ThreatFilters' + threat_indicator_path: + $ref: './specific_attributes/threat_match_attributes.schema.yaml#/components/schemas/ThreatIndicatorPath' + threat_language: + $ref: './common_attributes.schema.yaml#/components/schemas/KqlQueryLanguage' + concurrent_searches: + $ref: './specific_attributes/threat_match_attributes.schema.yaml#/components/schemas/ConcurrentSearches' + items_per_search: + $ref: './specific_attributes/threat_match_attributes.schema.yaml#/components/schemas/ItemsPerSearch' + + ThreatMatchRuleDefaultableFields: + type: object + properties: + language: + $ref: './common_attributes.schema.yaml#/components/schemas/KqlQueryLanguage' + + ThreatMatchRuleCreateFields: + allOf: + - $ref: '#/components/schemas/ThreatMatchRuleRequiredFields' + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - $ref: '#/components/schemas/ThreatMatchRuleDefaultableFields' + + ThreatMatchRulePatchFields: + allOf: + - $ref: '#/components/schemas/ThreatMatchRuleRequiredFields' + x-modify: partial + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - $ref: '#/components/schemas/ThreatMatchRuleDefaultableFields' + + ThreatMatchRuleResponseFields: + allOf: + - $ref: '#/components/schemas/ThreatMatchRuleRequiredFields' + - $ref: '#/components/schemas/ThreatMatchRuleOptionalFields' + - $ref: '#/components/schemas/ThreatMatchRuleDefaultableFields' + x-modify: required + + ThreatMatchRule: + allOf: + - $ref: '#/components/schemas/SharedResponseProps' + - $ref: '#/components/schemas/ThreatMatchRuleResponseFields' + + ThreatMatchRuleCreateProps: + allOf: + - $ref: '#/components/schemas/SharedCreateProps' + - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' + + ThreatMatchRuleUpdateProps: + allOf: + - $ref: '#/components/schemas/SharedUpdateProps' + - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' + + ThreatMatchRulePatchProps: + allOf: + - $ref: '#/components/schemas/SharedPatchProps' + - $ref: '#/components/schemas/ThreatMatchRulePatchFields' + + ########### + # ML Rule # + ########### + + MachineLearningRuleRequiredFields: + type: object + properties: + type: type: string - description: Technique reference - subtechnique: - type: array - items: - $ref: '#/components/schemas/Subtechnique' - description: Array containing more specific information on the attack technique + enum: [machine_learning] + description: Rule type + anomaly_threshold: + $ref: './specific_attributes/ml_attributes.schema.yaml#/components/schemas/AnomalyThreshold' + machine_learning_job_id: + $ref: './specific_attributes/ml_attributes.schema.yaml#/components/schemas/MachineLearningJobId' required: - - id - - name - - reference + - type + - machine_learning_job_id + - anomaly_threshold + + MachineLearningRulePatchFields: + allOf: + - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + x-modify: partial - Threat: + MachineLearningRuleResponseFields: + allOf: + - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + + MachineLearningRuleCreateFields: + allOf: + - $ref: '#/components/schemas/MachineLearningRuleRequiredFields' + + MachineLearningRule: + allOf: + - $ref: '#/components/schemas/SharedResponseProps' + - $ref: '#/components/schemas/MachineLearningRuleResponseFields' + + MachineLearningRuleCreateProps: + allOf: + - $ref: '#/components/schemas/SharedCreateProps' + - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + + MachineLearningRuleUpdateProps: + allOf: + - $ref: '#/components/schemas/SharedUpdateProps' + - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + + MachineLearningRulePatchProps: + allOf: + - $ref: '#/components/schemas/SharedPatchProps' + - $ref: '#/components/schemas/MachineLearningRulePatchFields' + + ################## + # New Terms Rule # + ################## + + NewTermsRuleRequiredFields: type: object properties: - framework: + type: type: string - description: Relevant attack framework - tactic: - type: object - properties: - id: - type: string - description: Tactic ID - name: - type: string - description: Tactic name - reference: - type: string - description: Tactic reference - required: - - id - - name - - reference - technique: - type: array - items: - $ref: '#/components/schemas/Technique' - description: Array containing information on the attack techniques (optional) + enum: [new_terms] + description: Rule type + query: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' + new_terms_fields: + $ref: './specific_attributes/new_terms_attributes.schema.yaml#/components/schemas/NewTermsFields' + history_window_start: + $ref: './specific_attributes/new_terms_attributes.schema.yaml#/components/schemas/HistoryWindowStart' required: - - framework - - tactic + - type + - query + - new_terms_fields + - history_window_start - RuleResponse: + NewTermsRuleOptionalFields: type: object + properties: + index: + $ref: './common_attributes.schema.yaml#/components/schemas/IndexPatternArray' + data_view_id: + $ref: './common_attributes.schema.yaml#/components/schemas/DataViewId' + filters: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleFilterArray' - RuleCreateProps: + NewTermsRuleDefaultableFields: type: object + properties: + language: + $ref: './common_attributes.schema.yaml#/components/schemas/KqlQueryLanguage' - RuleUpdateProps: + NewTermsRulePatchFields: + allOf: + - $ref: '#/components/schemas/NewTermsRuleRequiredFields' + x-modify: partial + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - $ref: '#/components/schemas/NewTermsRuleDefaultableFields' + + NewTermsRuleResponseFields: + allOf: + - $ref: '#/components/schemas/NewTermsRuleRequiredFields' + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - $ref: '#/components/schemas/NewTermsRuleDefaultableFields' + x-modify: required + + NewTermsRuleCreateFields: + allOf: + - $ref: '#/components/schemas/NewTermsRuleRequiredFields' + - $ref: '#/components/schemas/NewTermsRuleOptionalFields' + - $ref: '#/components/schemas/NewTermsRuleDefaultableFields' + + NewTermsRule: + allOf: + - $ref: '#/components/schemas/SharedResponseProps' + - $ref: '#/components/schemas/NewTermsRuleResponseFields' + + NewTermsRuleCreateProps: + allOf: + - $ref: '#/components/schemas/SharedCreateProps' + - $ref: '#/components/schemas/NewTermsRuleCreateFields' + + NewTermsRuleUpdateProps: + allOf: + - $ref: '#/components/schemas/SharedUpdateProps' + - $ref: '#/components/schemas/NewTermsRuleCreateFields' + + NewTermsRulePatchProps: + allOf: + - $ref: '#/components/schemas/SharedPatchProps' + - $ref: '#/components/schemas/NewTermsRulePatchFields' + + ########### + # ESQL Rule # + ########### + + EsqlQueryLanguage: + type: string + enum: + - esql + + EsqlRuleRequiredFields: type: object + properties: + type: + type: string + enum: [esql] + description: Rule type + language: + $ref: '#/components/schemas/EsqlQueryLanguage' + query: + $ref: './common_attributes.schema.yaml#/components/schemas/RuleQuery' + description: ESQL query to execute + required: + - type + - language + - query + + EsqlRulePatchFields: + allOf: + - $ref: '#/components/schemas/EsqlRuleRequiredFields' + x-modify: partial + + EsqlRuleResponseFields: + allOf: + - $ref: '#/components/schemas/EsqlRuleRequiredFields' + + EsqlRuleCreateFields: + allOf: + - $ref: '#/components/schemas/EsqlRuleRequiredFields' + + EsqlRule: + allOf: + - $ref: '#/components/schemas/SharedResponseProps' + - $ref: '#/components/schemas/EsqlRuleResponseFields' + + EsqlRuleCreateProps: + allOf: + - $ref: '#/components/schemas/SharedCreateProps' + - $ref: '#/components/schemas/EsqlRuleCreateFields' + + EsqlRuleUpdateProps: + allOf: + - $ref: '#/components/schemas/SharedUpdateProps' + - $ref: '#/components/schemas/EsqlRuleCreateFields' + + EsqlRulePatchProps: + allOf: + - $ref: '#/components/schemas/SharedPatchProps' + - $ref: '#/components/schemas/EsqlRulePatchFields' + x-modify: partial + + ########################## + # Final combined schemas # + ########################## + + TypeSpecificCreateProps: + anyOf: + - $ref: '#/components/schemas/EqlRuleCreateFields' + - $ref: '#/components/schemas/QueryRuleCreateFields' + - $ref: '#/components/schemas/SavedQueryRuleCreateFields' + - $ref: '#/components/schemas/ThresholdRuleCreateFields' + - $ref: '#/components/schemas/ThreatMatchRuleCreateFields' + - $ref: '#/components/schemas/MachineLearningRuleCreateFields' + - $ref: '#/components/schemas/NewTermsRuleCreateFields' + - $ref: '#/components/schemas/EsqlRuleCreateFields' + + TypeSpecificPatchProps: + anyOf: + - $ref: '#/components/schemas/EqlRulePatchFields' + - $ref: '#/components/schemas/QueryRulePatchFields' + - $ref: '#/components/schemas/SavedQueryRulePatchFields' + - $ref: '#/components/schemas/ThresholdRulePatchFields' + - $ref: '#/components/schemas/ThreatMatchRulePatchFields' + - $ref: '#/components/schemas/MachineLearningRulePatchFields' + - $ref: '#/components/schemas/NewTermsRulePatchFields' + - $ref: '#/components/schemas/EsqlRulePatchFields' + + TypeSpecificResponse: + anyOf: + - $ref: '#/components/schemas/EqlRuleResponseFields' + - $ref: '#/components/schemas/QueryRuleResponseFields' + - $ref: '#/components/schemas/SavedQueryRuleResponseFields' + - $ref: '#/components/schemas/ThresholdRuleResponseFields' + - $ref: '#/components/schemas/ThreatMatchRuleResponseFields' + - $ref: '#/components/schemas/MachineLearningRuleResponseFields' + - $ref: '#/components/schemas/NewTermsRuleResponseFields' + - $ref: '#/components/schemas/EsqlRuleResponseFields' + + RuleCreateProps: + anyOf: + - $ref: '#/components/schemas/EqlRuleCreateProps' + - $ref: '#/components/schemas/QueryRuleCreateProps' + - $ref: '#/components/schemas/SavedQueryRuleCreateProps' + - $ref: '#/components/schemas/ThresholdRuleCreateProps' + - $ref: '#/components/schemas/ThreatMatchRuleCreateProps' + - $ref: '#/components/schemas/MachineLearningRuleCreateProps' + - $ref: '#/components/schemas/NewTermsRuleCreateProps' + - $ref: '#/components/schemas/EsqlRuleCreateProps' + + RuleUpdateProps: + anyOf: + - $ref: '#/components/schemas/EqlRuleUpdateProps' + - $ref: '#/components/schemas/QueryRuleUpdateProps' + - $ref: '#/components/schemas/SavedQueryRuleUpdateProps' + - $ref: '#/components/schemas/ThresholdRuleUpdateProps' + - $ref: '#/components/schemas/ThreatMatchRuleUpdateProps' + - $ref: '#/components/schemas/MachineLearningRuleUpdateProps' + - $ref: '#/components/schemas/NewTermsRuleUpdateProps' + - $ref: '#/components/schemas/EsqlRuleUpdateProps' RulePatchProps: - type: object + anyOf: + - $ref: '#/components/schemas/EqlRulePatchProps' + - $ref: '#/components/schemas/QueryRulePatchProps' + - $ref: '#/components/schemas/SavedQueryRulePatchProps' + - $ref: '#/components/schemas/ThresholdRulePatchProps' + - $ref: '#/components/schemas/ThreatMatchRulePatchProps' + - $ref: '#/components/schemas/MachineLearningRulePatchProps' + - $ref: '#/components/schemas/NewTermsRulePatchProps' + - $ref: '#/components/schemas/EsqlRulePatchProps' + + RuleResponse: + anyOf: + - $ref: '#/components/schemas/EqlRule' + - $ref: '#/components/schemas/QueryRule' + - $ref: '#/components/schemas/SavedQueryRule' + - $ref: '#/components/schemas/ThresholdRule' + - $ref: '#/components/schemas/ThreatMatchRule' + - $ref: '#/components/schemas/MachineLearningRule' + - $ref: '#/components/schemas/NewTermsRule' + - $ref: '#/components/schemas/EsqlRule' diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/eql_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/eql_attributes.gen.ts new file mode 100644 index 00000000000000..63fa41e0475485 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/eql_attributes.gen.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +export type EventCategoryOverride = z.infer; +export const EventCategoryOverride = z.string(); + +/** + * Contains the event timestamp used for sorting a sequence of events + */ +export type TimestampField = z.infer; +export const TimestampField = z.string(); + +/** + * Sets a secondary field for sorting events + */ +export type TiebreakerField = z.infer; +export const TiebreakerField = z.string(); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/eql_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/eql_attributes.schema.yaml new file mode 100644 index 00000000000000..6b6065ea382200 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/eql_attributes.schema.yaml @@ -0,0 +1,16 @@ +openapi: 3.0.0 +info: + title: EQL Rule Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + EventCategoryOverride: + type: string + TimestampField: + type: string + description: Contains the event timestamp used for sorting a sequence of events + TiebreakerField: + type: string + description: Sets a secondary field for sorting events diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/ml_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/ml_attributes.gen.ts new file mode 100644 index 00000000000000..7350dde5e7c2be --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/ml_attributes.gen.ts @@ -0,0 +1,25 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +/** + * Anomaly threshold + */ +export type AnomalyThreshold = z.infer; +export const AnomalyThreshold = z.number().int().min(0); + +/** + * Machine learning job ID + */ +export type MachineLearningJobId = z.infer; +export const MachineLearningJobId = z.union([z.string(), z.array(z.string()).min(1)]); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/ml_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/ml_attributes.schema.yaml new file mode 100644 index 00000000000000..414e51393d972c --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/ml_attributes.schema.yaml @@ -0,0 +1,20 @@ +openapi: 3.0.0 +info: + title: ML Rule Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + AnomalyThreshold: + type: integer + minimum: 0 + description: Anomaly threshold + MachineLearningJobId: + oneOf: + - type: string + - type: array + items: + type: string + minItems: 1 + description: Machine learning job ID diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.gen.ts new file mode 100644 index 00000000000000..f5b0b751d44525 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.gen.ts @@ -0,0 +1,21 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { NonEmptyString } from '../common_attributes.gen'; + +export type NewTermsFields = z.infer; +export const NewTermsFields = z.array(z.string()).min(1).max(3); + +export type HistoryWindowStart = z.infer; +export const HistoryWindowStart = NonEmptyString; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.schema.yaml new file mode 100644 index 00000000000000..4281cd3121f405 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.schema.yaml @@ -0,0 +1,16 @@ +openapi: 3.0.0 +info: + title: New Terms Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + NewTermsFields: + type: array + items: + type: string + minItems: 1 + maxItems: 3 + HistoryWindowStart: + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.gen.ts new file mode 100644 index 00000000000000..a21edeeb6831fa --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.gen.ts @@ -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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +/** + * Describes how alerts will be generated for documents with missing suppress by fields: +doNotSuppress - per each document a separate alert will be created +suppress - only alert will be created per suppress by bucket + */ +export type AlertSuppressionMissingFieldsStrategy = z.infer< + typeof AlertSuppressionMissingFieldsStrategy +>; +export const AlertSuppressionMissingFieldsStrategy = z.enum(['doNotSuppress', 'suppress']); +export type AlertSuppressionMissingFieldsStrategyEnum = + typeof AlertSuppressionMissingFieldsStrategy.enum; +export const AlertSuppressionMissingFieldsStrategyEnum = AlertSuppressionMissingFieldsStrategy.enum; + +export type AlertSuppressionGroupBy = z.infer; +export const AlertSuppressionGroupBy = z.array(z.string()).min(1).max(3); + +export type AlertSuppressionDuration = z.infer; +export const AlertSuppressionDuration = z.object({ + value: z.number().int().min(1), + unit: z.enum(['s', 'm', 'h']), +}); + +export type AlertSuppression = z.infer; +export const AlertSuppression = z.object({ + group_by: AlertSuppressionGroupBy, + duration: AlertSuppressionDuration.optional(), + missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.optional(), +}); + +export type AlertSuppressionCamel = z.infer; +export const AlertSuppressionCamel = z.object({ + groupBy: AlertSuppressionGroupBy, + duration: AlertSuppressionDuration.optional(), + missingFieldsStrategy: AlertSuppressionMissingFieldsStrategy.optional(), +}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.schema.yaml new file mode 100644 index 00000000000000..36581c44e3d35c --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.schema.yaml @@ -0,0 +1,64 @@ +openapi: 3.0.0 +info: + title: Query Rule Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + AlertSuppressionMissingFieldsStrategy: + type: string + enum: + - doNotSuppress + - suppress + description: |- + Describes how alerts will be generated for documents with missing suppress by fields: + doNotSuppress - per each document a separate alert will be created + suppress - only alert will be created per suppress by bucket + + AlertSuppressionGroupBy: + type: array + items: + type: string + minItems: 1 + maxItems: 3 + + AlertSuppressionDuration: + type: object + properties: + value: + type: integer + minimum: 1 + unit: + type: string + enum: + - s + - m + - h + required: + - value + - unit + + AlertSuppression: + type: object + properties: + group_by: + $ref: '#/components/schemas/AlertSuppressionGroupBy' + duration: + $ref: '#/components/schemas/AlertSuppressionDuration' + missing_fields_strategy: + $ref: '#/components/schemas/AlertSuppressionMissingFieldsStrategy' + required: + - group_by + + AlertSuppressionCamel: + type: object + properties: + groupBy: + $ref: '#/components/schemas/AlertSuppressionGroupBy' + duration: + $ref: '#/components/schemas/AlertSuppressionDuration' + missingFieldsStrategy: + $ref: '#/components/schemas/AlertSuppressionMissingFieldsStrategy' + required: + - groupBy diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.gen.ts new file mode 100644 index 00000000000000..14f2bcf047b5f1 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.gen.ts @@ -0,0 +1,54 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { NonEmptyString } from '../common_attributes.gen'; + +/** + * Query to execute + */ +export type ThreatQuery = z.infer; +export const ThreatQuery = z.string(); + +export type ThreatMapping = z.infer; +export const ThreatMapping = z + .array( + z.object({ + entries: z.array( + z.object({ + field: NonEmptyString, + type: z.literal('mapping'), + value: NonEmptyString, + }) + ), + }) + ) + .min(1); + +export type ThreatIndex = z.infer; +export const ThreatIndex = z.array(z.string()); + +export type ThreatFilters = z.infer; +export const ThreatFilters = z.array(z.unknown()); + +/** + * Defines the path to the threat indicator in the indicator documents (optional) + */ +export type ThreatIndicatorPath = z.infer; +export const ThreatIndicatorPath = z.string(); + +export type ConcurrentSearches = z.infer; +export const ConcurrentSearches = z.number().int().min(1); + +export type ItemsPerSearch = z.infer; +export const ItemsPerSearch = z.number().int().min(1); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.schema.yaml new file mode 100644 index 00000000000000..aa0cfd68dc0678 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threat_match_attributes.schema.yaml @@ -0,0 +1,59 @@ +openapi: 3.0.0 +info: + title: Threat Match Rule Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + ThreatQuery: + type: string + description: Query to execute + + ThreatMapping: + type: array + minItems: 1 + items: + type: object + properties: + entries: + type: array + items: + type: object + properties: + field: + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' + type: + type: string + enum: + - mapping + value: + $ref: '../common_attributes.schema.yaml#/components/schemas/NonEmptyString' + required: + - field + - type + - value + required: + - entries + + ThreatIndex: + type: array + items: + type: string + + ThreatFilters: + type: array + items: + description: Query and filter context array used to filter documents from the Elasticsearch index containing the threat values + + ThreatIndicatorPath: + type: string + description: Defines the path to the threat indicator in the indicator documents (optional) + + ConcurrentSearches: + type: integer + minimum: 1 + + ItemsPerSearch: + type: integer + minimum: 1 diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes.gen.ts new file mode 100644 index 00000000000000..46a48dae05abfb --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes.gen.ts @@ -0,0 +1,60 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +export type ThresholdCardinality = z.infer; +export const ThresholdCardinality = z.array( + z.object({ + field: z.string(), + value: z.number().int().min(0), + }) +); + +/** + * Threshold value + */ +export type ThresholdValue = z.infer; +export const ThresholdValue = z.number().int().min(1); + +/** + * Field to aggregate on + */ +export type ThresholdField = z.infer; +export const ThresholdField = z.union([z.string(), z.array(z.string())]); + +/** + * Field to aggregate on + */ +export type ThresholdFieldNormalized = z.infer; +export const ThresholdFieldNormalized = z.array(z.string()); + +export type Threshold = z.infer; +export const Threshold = z.object({ + field: ThresholdField, + value: ThresholdValue, + cardinality: ThresholdCardinality.optional(), +}); + +export type ThresholdNormalized = z.infer; +export const ThresholdNormalized = z.object({ + field: ThresholdFieldNormalized, + value: ThresholdValue, + cardinality: ThresholdCardinality.optional(), +}); + +export type ThresholdWithCardinality = z.infer; +export const ThresholdWithCardinality = z.object({ + field: ThresholdFieldNormalized, + value: ThresholdValue, + cardinality: ThresholdCardinality, +}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes.schema.yaml new file mode 100644 index 00000000000000..4be7e45ba1012b --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes.schema.yaml @@ -0,0 +1,80 @@ +openapi: 3.0.0 +info: + title: Threshold Rule Attributes + version: 'not applicable' +paths: {} +components: + x-codegen-enabled: true + schemas: + ThresholdCardinality: + type: array + items: + type: object + properties: + field: + type: string + value: + type: integer + minimum: 0 + required: + - field + - value + + ThresholdValue: + type: integer + minimum: 1 + description: Threshold value + + ThresholdField: + oneOf: + - type: string + - type: array + items: + type: string + description: Field to aggregate on + + ThresholdFieldNormalized: + type: array + items: + type: string + description: Field to aggregate on + + Threshold: + type: object + properties: + field: + $ref: '#/components/schemas/ThresholdField' + value: + $ref: '#/components/schemas/ThresholdValue' + cardinality: + $ref: '#/components/schemas/ThresholdCardinality' + required: + - field + - value + + ThresholdNormalized: + type: object + properties: + field: + $ref: '#/components/schemas/ThresholdFieldNormalized' + value: + $ref: '#/components/schemas/ThresholdValue' + cardinality: + $ref: '#/components/schemas/ThresholdCardinality' + required: + - field + - value + + ThresholdWithCardinality: + type: object + properties: + field: + $ref: '#/components/schemas/ThresholdFieldNormalized' + value: + $ref: '#/components/schemas/ThresholdValue' + cardinality: + $ref: '#/components/schemas/ThresholdCardinality' + required: + - field + - value + - cardinality diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/common_attributes.ts similarity index 99% rename from x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/common_attributes.ts index 9e0035e3e972b2..310f96b7bf946c 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/common_attributes.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/common_attributes.ts @@ -44,7 +44,7 @@ export const RuleTagArray = t.array(t.string); // should be non-empty strings? * to be added to the meta object */ export type RuleMetadata = t.TypeOf; -export const RuleMetadata = t.object; // should be a more specific type? +export const RuleMetadata = t.UnknownRecord; // should be a more specific type? export type RuleLicense = t.TypeOf; export const RuleLicense = t.string; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/eql_attributes.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/eql_attributes.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/eql_attributes.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/eql_attributes.ts diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/index.ts similarity index 51% rename from x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/index.ts index 07bef679e41ace..6fbe808a0eb480 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/index.ts @@ -5,9 +5,11 @@ * 2.0. */ -import * as t from 'io-ts'; +export * from './common_attributes'; -import { RuleResponse, ErrorSchema } from '../../model'; +export * from './eql_attributes'; +export * from './new_terms_attributes'; +export * from './query_attributes'; +export * from './threshold_attributes'; -export type BulkCrudRulesResponse = t.TypeOf; -export const BulkCrudRulesResponse = t.array(t.union([RuleResponse, ErrorSchema])); +export * from './rule_schemas'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/new_terms_attributes.ts similarity index 92% rename from x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/new_terms_attributes.ts index fa3e8e58601165..6d9f39011b675c 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/new_terms_attributes.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/new_terms_attributes.ts @@ -7,7 +7,7 @@ import * as t from 'io-ts'; import { LimitedSizeArray, NonEmptyString } from '@kbn/securitysolution-io-ts-types'; -import { MAX_NUMBER_OF_NEW_TERMS_FIELDS } from '../../../../../constants'; +import { MAX_NUMBER_OF_NEW_TERMS_FIELDS } from '../../../../constants'; // Attributes specific to New Terms rules diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/query_attributes.ts similarity index 78% rename from x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/query_attributes.ts index a3d5d56698d9c8..f6090383a3ce3b 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/query_attributes.ts @@ -11,24 +11,13 @@ import { PositiveIntegerGreaterThanZero, enumeration, } from '@kbn/securitysolution-io-ts-types'; - -/** - * describes how alerts will be generated for documents with missing suppress by fields - */ -export enum AlertSuppressionMissingFieldsStrategy { - // per each document a separate alert will be created - DoNotSuppress = 'doNotSuppress', - // only alert will be created per suppress by bucket - Suppress = 'suppress', -} +import { AlertSuppressionMissingFieldsStrategyEnum } from '../rule_schema/specific_attributes/query_attributes.gen'; export type AlertSuppressionMissingFields = t.TypeOf; export const AlertSuppressionMissingFields = enumeration( 'AlertSuppressionMissingFields', - AlertSuppressionMissingFieldsStrategy + AlertSuppressionMissingFieldsStrategyEnum ); -export const DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY = - AlertSuppressionMissingFieldsStrategy.Suppress; export const AlertSuppressionGroupBy = LimitedSizeArray({ codec: t.string, @@ -79,5 +68,3 @@ export const AlertSuppressionCamel = t.intersection([ }) ), ]); - -export const minimumLicenseForSuppression = 'platinum'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/rule_schemas.ts similarity index 89% rename from x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/rule_schemas.ts index 0c4071894f99e5..e95fa38e0d2e65 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/rule_schemas.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/rule_schemas.ts @@ -28,15 +28,17 @@ import { } from '@kbn/securitysolution-io-ts-alerting-types'; import { RuleExecutionSummary } from '../../rule_monitoring/model'; -import { ResponseActionArray } from '../rule_response_actions'; +// eslint-disable-next-line no-restricted-imports +import { ResponseActionArray } from '../rule_response_actions/response_actions_legacy'; + import { - saved_id, anomaly_threshold, - updated_at, - updated_by, created_at, created_by, revision, + saved_id, + updated_at, + updated_by, } from '../schemas'; import { @@ -46,6 +48,7 @@ import { DataViewId, ExceptionListArray, IndexPatternArray, + InvestigationFields, InvestigationGuide, IsRuleEnabled, IsRuleImmutable, @@ -53,7 +56,6 @@ import { RelatedIntegrationArray, RequiredFieldArray, RuleAuthorArray, - InvestigationFields, RuleDescription, RuleFalsePositiveArray, RuleFilterArray, @@ -77,16 +79,53 @@ import { TimestampOverride, TimestampOverrideFallbackDisabled, } from './common_attributes'; -import { - EventCategoryOverride, - TiebreakerField, - TimestampField, -} from './specific_attributes/eql_attributes'; -import { Threshold } from './specific_attributes/threshold_attributes'; -import { HistoryWindowStart, NewTermsFields } from './specific_attributes/new_terms_attributes'; -import { AlertSuppression } from './specific_attributes/query_attributes'; +import { EventCategoryOverride, TiebreakerField, TimestampField } from './eql_attributes'; +import { HistoryWindowStart, NewTermsFields } from './new_terms_attributes'; +import { AlertSuppression } from './query_attributes'; +import { Threshold } from './threshold_attributes'; + +export const buildRuleSchemas = < + Required extends t.Props, + Optional extends t.Props, + Defaultable extends t.Props +>({ + required, + optional, + defaultable, +}: { + required: Required; + optional: Optional; + defaultable: Defaultable; +}) => ({ + create: t.intersection([ + t.exact(t.type(required)), + t.exact(t.partial(optional)), + t.exact(t.partial(defaultable)), + ]), + patch: t.intersection([t.partial(required), t.partial(optional), t.partial(defaultable)]), + response: t.intersection([ + t.exact(t.type(required)), + // This bit of logic is to force all fields to be accounted for in conversions from the internal + // rule schema to the response schema. Rather than use `t.partial`, which makes each field optional, + // we make each field required but possibly undefined. The result is that if a field is forgotten in + // the conversion from internal schema to response schema TS will report an error. If we just used t.partial + // instead, then optional fields can be accidentally omitted from the conversion - and any actual values + // in those fields internally will be stripped in the response. + t.exact(t.type(orUndefined(optional))), + t.exact(t.type(defaultable)), + ]), +}); -import { buildRuleSchemas } from './build_rule_schemas'; +export type OrUndefined

= { + [K in keyof P]: P[K] | t.UndefinedC; +}; + +export const orUndefined =

(props: P): OrUndefined

=> { + return Object.keys(props).reduce((acc, key) => { + acc[key] = t.union([props[key], t.undefined]); + return acc; + }, {}) as OrUndefined

; +}; // ------------------------------------------------------------------------------------------------- // Base schema @@ -106,7 +145,7 @@ export const baseSchema = buildRuleSchemas({ // Timeline template timeline_id: TimelineTemplateId, timeline_title: TimelineTemplateTitle, - // Atributes related to SavedObjectsClient.resolve API + // Attributes related to SavedObjectsClient.resolve API outcome: SavedObjectResolveOutcome, alias_target_id: SavedObjectResolveAliasTargetId, alias_purpose: SavedObjectResolveAliasPurpose, @@ -578,4 +617,4 @@ export type RulePatchProps = t.TypeOf; export const RulePatchProps = t.intersection([TypeSpecificPatchProps, SharedPatchProps]); export type RuleResponse = t.TypeOf; -export const RuleResponse = t.intersection([SharedResponseProps, TypeSpecificResponse]); +export const RuleResponse = t.intersection([TypeSpecificResponse, SharedResponseProps]); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/threshold_attributes.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/rule_schema_legacy/threshold_attributes.ts diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts index 7e8cb0ebbe58b3..9c325d1e70fc03 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/schemas.ts @@ -89,10 +89,6 @@ export const indexRecord = t.record( }) ); -export const indexType = t.type({ - index: indexRecord, -}); - export const privilege = t.type({ username: t.string, has_all_requested: t.boolean, diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.gen.ts index b2206c5a381ef8..3b9d0a8fa02c04 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.gen.ts @@ -14,5 +14,5 @@ import { z } from 'zod'; export type SortOrder = z.infer; export const SortOrder = z.enum(['asc', 'desc']); -export const SortOrderEnum = SortOrder.enum; export type SortOrderEnum = typeof SortOrder.enum; +export const SortOrderEnum = SortOrder.enum; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.test.ts index f0d6638740e324..17ad724039d7e2 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.test.ts @@ -8,7 +8,9 @@ import { pipe } from 'fp-ts/lib/pipeable'; import { left } from 'fp-ts/lib/Either'; import { foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { DefaultSortOrderAsc, DefaultSortOrderDesc } from './sorting'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { DefaultSortOrderAsc, DefaultSortOrderDesc } from './sorting_legacy'; describe('Common sorting schemas', () => { describe('DefaultSortOrderAsc', () => { diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/sorting_legacy.ts similarity index 100% rename from x-pack/plugins/security_solution/common/api/detection_engine/model/sorting.ts rename to x-pack/plugins/security_solution/common/api/detection_engine/model/sorting_legacy.ts diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/model/warning_schema.ts b/x-pack/plugins/security_solution/common/api/detection_engine/model/warning_schema.ts deleted file mode 100644 index 9f82dc5db06056..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/model/warning_schema.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; - -const partial = t.exact( - t.partial({ - buttonLabel: t.string, - }) -); -const required = t.exact( - t.type({ - type: t.string, - message: t.string, - actionPath: t.string, - }) -); - -export const WarningSchema = t.intersection([partial, required]); -export type WarningSchema = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.test.ts index 8be56e9d414164..1dcf57d10fb504 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/get_prebuilt_rules_and_timelines_status/get_prebuilt_rules_and_timelines_status_route.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { stringifyZodError } from '@kbn/securitysolution-es-utils'; -import { expectParseError, expectParseSuccess } from '../../../../test/zod_helpers'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { GetPrebuiltRulesAndTimelinesStatusResponse } from './get_prebuilt_rules_and_timelines_status_route.gen'; describe('Get prebuilt rules and timelines status response schema', () => { diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.test.ts index 5edbd070b39726..760b9b7db143a3 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/install_prebuilt_rules_and_timelines/install_prebuilt_rules_and_timelines_route.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { stringifyZodError } from '@kbn/securitysolution-es-utils'; -import { expectParseError, expectParseSuccess } from '../../../../test/zod_helpers'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { InstallPrebuiltRulesAndTimelinesResponse } from './install_prebuilt_rules_and_timelines_route.gen'; describe('Install prebuilt rules and timelines response schema', () => { diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/build_schema.ts b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/build_schema.ts index b57882ffdfc5cc..b1d7752fb9f893 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/build_schema.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/build_schema.ts @@ -6,7 +6,9 @@ */ import * as t from 'io-ts'; -import { orUndefined } from '../../../../model'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { orUndefined } from '../../../../model/rule_schema_legacy'; interface RuleFields { required: TRequired; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_field_types.ts b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_field_types.ts index cde6305c91858f..299b4a7d7b3944 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_field_types.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_field_types.ts @@ -7,6 +7,8 @@ import * as t from 'io-ts'; import { TimeDuration } from '@kbn/securitysolution-io-ts-types'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports import { BuildingBlockType, DataViewId, @@ -19,8 +21,8 @@ import { TimelineTemplateTitle, TimestampOverride as TimestampOverrideFieldName, TimestampOverrideFallbackDisabled, - saved_id, -} from '../../../../model'; +} from '../../../../model/rule_schema_legacy'; +import { saved_id } from '../../../../model/schemas'; // ------------------------------------------------------------------------------------------------- // Rule data source diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_rule.ts b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_rule.ts index b88597a569d899..ac53a3c695d47a 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_rule.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/model/diff/diffable_rule/diffable_rule.ts @@ -22,6 +22,8 @@ import { threat_mapping, } from '@kbn/securitysolution-io-ts-alerting-types'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports import { AlertSuppression, EventCategoryOverride, @@ -47,8 +49,7 @@ import { Threshold, TiebreakerField, TimestampField, - anomaly_threshold, -} from '../../../../model'; +} from '../../../../model/rule_schema_legacy'; import { BuildingBlockObject, @@ -64,6 +65,7 @@ import { } from './diffable_field_types'; import { buildSchema } from './build_schema'; +import { anomaly_threshold } from '../../../../model/schemas'; export type DiffableCommonFields = t.TypeOf; export const DiffableCommonFields = buildSchema({ diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/review_rule_installation/review_rule_installation_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/review_rule_installation/review_rule_installation_route.ts index ddb452a73079e1..e3c20db98ab7e1 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/review_rule_installation/review_rule_installation_route.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/review_rule_installation/review_rule_installation_route.ts @@ -6,7 +6,7 @@ */ import type { RuleTagArray } from '../../model'; -import type { RuleResponse } from '../../model/rule_schema/rule_schemas'; +import type { RuleResponse } from '../../model/rule_schema'; export interface ReviewRuleInstallationResponseBody { /** Aggregated info about all rules available for installation */ diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/review_rule_upgrade/review_rule_upgrade_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/review_rule_upgrade/review_rule_upgrade_route.ts index 994e5908d39337..09067a2e152e14 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/review_rule_upgrade/review_rule_upgrade_route.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/prebuilt_rules/review_rule_upgrade/review_rule_upgrade_route.ts @@ -7,7 +7,7 @@ import type { RuleObjectId, RuleSignatureId, RuleTagArray } from '../../model'; import type { PartialRuleDiff } from '../model'; -import type { RuleResponse } from '../../model/rule_schema/rule_schemas'; +import type { RuleResponse } from '../../model/rule_schema'; export interface ReviewRuleUpgradeResponseBody { /** Aggregated info about all rules available for upgrade */ diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/create_rule_exceptions/create_rule_exceptions_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/create_rule_exceptions/create_rule_exceptions_route.ts index 42ef5482b5b5a2..feecf23faf2939 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/create_rule_exceptions/create_rule_exceptions_route.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/create_rule_exceptions/create_rule_exceptions_route.ts @@ -12,8 +12,9 @@ import type { ExceptionListItemSchema, } from '@kbn/securitysolution-io-ts-list-types'; import { createRuleExceptionListItemSchema } from '@kbn/securitysolution-io-ts-list-types'; - -import { RuleObjectId } from '../../model'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { RuleObjectId } from '../../model/rule_schema_legacy'; /** * URL path parameters of the API route. diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/find_exception_references/find_exception_references_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/find_exception_references/find_exception_references_route.ts index e495ab96477259..cbef9a41de7182 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/find_exception_references/find_exception_references_route.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_exceptions/find_exception_references/find_exception_references_route.ts @@ -13,7 +13,9 @@ import { DefaultNamespaceArray, } from '@kbn/securitysolution-io-ts-list-types'; import { NonEmptyStringArray } from '@kbn/securitysolution-io-ts-types'; -import { RuleName, RuleObjectId, RuleSignatureId } from '../../model'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { RuleName, RuleObjectId, RuleSignatureId } from '../../model/rule_schema_legacy'; // If ids and list_ids are undefined, route will fetch all lists matching the // specified namespace type diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.ts index 012c3dbf731495..768626d08769dd 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_actions/bulk_actions_route.ts @@ -20,13 +20,15 @@ import type { BulkActionSkipResult } from '@kbn/alerting-plugin/common'; import type { RuleResponse } from '../../model'; import type { BulkActionsDryRunErrCode } from '../../../../constants'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports import { IndexPatternArray, RuleQuery, RuleTagArray, TimelineTemplateId, TimelineTemplateTitle, -} from '../../model'; +} from '../../model/rule_schema_legacy'; export enum BulkActionType { 'enable' = 'enable', diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.gen.ts new file mode 100644 index 00000000000000..84124ef5867da4 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.gen.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleCreateProps } from '../../../model/rule_schema/rule_schemas.gen'; +import { BulkCrudRulesResponse } from '../response_schema.gen'; + +export type BulkCreateRulesRequestBody = z.infer; +export const BulkCreateRulesRequestBody = z.array(RuleCreateProps); +export type BulkCreateRulesRequestBodyInput = z.input; + +export type BulkCreateRulesResponse = z.infer; +export const BulkCreateRulesResponse = BulkCrudRulesResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml index ca88e7aca4be05..ee02ec47c59b91 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.schema.yaml @@ -5,8 +5,8 @@ info: paths: /api/detection_engine/rules/_bulk_create: post: - operationId: CreateRulesBulk - x-codegen-enabled: false + operationId: BulkCreateRules + x-codegen-enabled: true deprecated: true description: Creates new detection rules in bulk. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts index bf06b41aef39b2..40955f2eba40a2 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { BulkCreateRulesRequestBody } from './bulk_create_rules_route'; -import { exactCheck, foldLeftRight, formatErrors } from '@kbn/securitysolution-io-ts-utils'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { getCreateRulesSchemaMock } from '../../../model/rule_schema/mocks'; +import { BulkCreateRulesRequestBody } from './bulk_create_rules_route.gen'; // only the basics of testing are here. // see: rule_schemas.test.ts for the bulk of the validation tests @@ -16,40 +16,25 @@ describe('Bulk create rules request schema', () => { test('can take an empty array and validate it', () => { const payload: BulkCreateRulesRequestBody = []; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(output.errors).toEqual([]); - expect(output.schema).toEqual([]); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('made up values do not validate for a single element', () => { const payload: Array<{ madeUp: string }> = [{ madeUp: 'hi' }]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toContain( - 'Invalid value "undefined" supplied to "description"' - ); - expect(formatErrors(output.errors)).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(formatErrors(output.errors)).toContain('Invalid value "undefined" supplied to "name"'); - expect(formatErrors(output.errors)).toContain( - 'Invalid value "undefined" supplied to "severity"' - ); - expect(output.schema).toEqual({}); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('single array element does validate', () => { const payload: BulkCreateRulesRequestBody = [getCreateRulesSchemaMock()]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('two array elements do validate', () => { @@ -58,11 +43,9 @@ describe('Bulk create rules request schema', () => { getCreateRulesSchemaMock(), ]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('single array element with a missing value (risk_score) will not validate', () => { @@ -71,13 +54,9 @@ describe('Bulk create rules request schema', () => { delete singleItem.risk_score; const payload: BulkCreateRulesRequestBody = [singleItem]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(output.schema).toEqual({}); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('two array elements where the first is valid but the second is invalid (risk_score) will not validate', () => { @@ -87,13 +66,9 @@ describe('Bulk create rules request schema', () => { delete secondItem.risk_score; const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(output.schema).toEqual({}); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"1: Invalid input"`); }); test('two array elements where the first is invalid (risk_score) but the second is valid will not validate', () => { @@ -103,13 +78,9 @@ describe('Bulk create rules request schema', () => { delete singleItem.risk_score; const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(output.schema).toEqual({}); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('two array elements where both are invalid (risk_score) will not validate', () => { @@ -121,46 +92,14 @@ describe('Bulk create rules request schema', () => { delete secondItem.risk_score; const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(output.schema).toEqual({}); - }); - - test('two array elements where the first is invalid (extra key and value) but the second is valid will not validate', () => { - const singleItem = { - ...getCreateRulesSchemaMock(), - madeUpValue: 'something', - }; - const secondItem = getCreateRulesSchemaMock(); - const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue"']); - expect(output.schema).toEqual({}); - }); - - test('two array elements where the second is invalid (extra key and value) but the first is valid will not validate', () => { - const singleItem = getCreateRulesSchemaMock(); - const secondItem = { - ...getCreateRulesSchemaMock(), - madeUpValue: 'something', - }; - const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue"']); - expect(output.schema).toEqual({}); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"0: Invalid input, 1: Invalid input"` + ); }); - test('two array elements where both are invalid (extra key and value) will not validate', () => { + test('extra keys are omitted from the payload', () => { const singleItem = { ...getCreateRulesSchemaMock(), madeUpValue: 'something', @@ -171,22 +110,18 @@ describe('Bulk create rules request schema', () => { }; const payload: BulkCreateRulesRequestBody = [singleItem, secondItem]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue,madeUpValue"']); - expect(output.schema).toEqual({}); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual([getCreateRulesSchemaMock(), getCreateRulesSchemaMock()]); }); test('You cannot set the severity to a value other than low, medium, high, or critical', () => { const badSeverity = { ...getCreateRulesSchemaMock(), severity: 'madeup' }; const payload = [badSeverity]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['Invalid value "madeup" supplied to "severity"']); - expect(output.schema).toEqual({}); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('You can set "note" to a string', () => { @@ -194,21 +129,17 @@ describe('Bulk create rules request schema', () => { { ...getCreateRulesSchemaMock(), note: '# test markdown' }, ]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set "note" to an empty string', () => { const payload: BulkCreateRulesRequestBody = [{ ...getCreateRulesSchemaMock(), note: '' }]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cant set "note" to anything other than string', () => { @@ -221,12 +152,8 @@ describe('Bulk create rules request schema', () => { }, ]; - const decoded = BulkCreateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "{"something":"some object"}" supplied to "note"', - ]); - expect(output.schema).toEqual({}); + const result = BulkCreateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.ts deleted file mode 100644 index 18f16cfdd3ce26..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_create_rules/bulk_create_rules_route.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { RuleCreateProps } from '../../../model'; - -/** - * Request body parameters of the API route. - */ -export type BulkCreateRulesRequestBody = t.TypeOf; -export const BulkCreateRulesRequestBody = t.array(RuleCreateProps); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.gen.ts new file mode 100644 index 00000000000000..b1b12e0ef1a858 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.gen.ts @@ -0,0 +1,28 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleObjectId, RuleSignatureId } from '../../../model/rule_schema/common_attributes.gen'; +import { BulkCrudRulesResponse } from '../response_schema.gen'; + +export type BulkDeleteRulesRequestBody = z.infer; +export const BulkDeleteRulesRequestBody = z.array( + z.object({ + id: RuleObjectId.optional(), + rule_id: RuleSignatureId.optional(), + }) +); +export type BulkDeleteRulesRequestBodyInput = z.input; + +export type BulkDeleteRulesResponse = z.infer; +export const BulkDeleteRulesResponse = BulkCrudRulesResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml index cf9ccf0853dcc9..85bdb7027447b9 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.schema.yaml @@ -5,8 +5,8 @@ info: paths: /api/detection_engine/rules/_bulk_delete: delete: - operationId: DeleteRulesBulk - x-codegen-enabled: false + operationId: BulkDeleteRules + x-codegen-enabled: true deprecated: true description: Deletes multiple rules. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.test.ts index cdb4085eea1ebf..90e5abf36163d8 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.test.ts @@ -5,8 +5,8 @@ * 2.0. */ -import { exactCheck, formatErrors, foldLeftRight } from '@kbn/securitysolution-io-ts-utils'; -import { BulkDeleteRulesRequestBody } from './bulk_delete_rules_route'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; +import { BulkDeleteRulesRequestBody } from './bulk_delete_rules_route.gen'; // only the basics of testing are here. // see: query_rules_schema.test.ts for the bulk of the validation tests @@ -15,11 +15,9 @@ describe('Bulk delete rules request schema', () => { test('can take an empty array and validate it', () => { const payload: BulkDeleteRulesRequestBody = []; - const decoded = BulkDeleteRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual([]); + const result = BulkDeleteRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('non uuid being supplied to id does not validate', () => { @@ -29,11 +27,9 @@ describe('Bulk delete rules request schema', () => { }, ]; - const decoded = BulkDeleteRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['Invalid value "1" supplied to "id"']); - expect(output.schema).toEqual({}); + const result = BulkDeleteRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0.id: Invalid uuid"`); }); test('both rule_id and id being supplied do validate', () => { @@ -44,11 +40,9 @@ describe('Bulk delete rules request schema', () => { }, ]; - const decoded = BulkDeleteRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkDeleteRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('only id validates with two elements', () => { @@ -57,11 +51,9 @@ describe('Bulk delete rules request schema', () => { { id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f' }, ]; - const decoded = BulkDeleteRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkDeleteRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('only rule_id validates', () => { @@ -69,11 +61,9 @@ describe('Bulk delete rules request schema', () => { { rule_id: 'c1e1b359-7ac1-4e96-bc81-c683c092436f' }, ]; - const decoded = BulkDeleteRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkDeleteRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('only rule_id validates with two elements', () => { @@ -82,11 +72,9 @@ describe('Bulk delete rules request schema', () => { { rule_id: '2' }, ]; - const decoded = BulkDeleteRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkDeleteRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('both id and rule_id validates with two separate elements', () => { @@ -95,10 +83,8 @@ describe('Bulk delete rules request schema', () => { { rule_id: '2' }, ]; - const decoded = BulkDeleteRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkDeleteRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.ts deleted file mode 100644 index 0da4acf82f546b..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_delete_rules/bulk_delete_rules_route.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { QueryRuleByIds } from '../../model/query_rule_by_ids'; - -/** - * Request body parameters of the API route. - */ -export type BulkDeleteRulesRequestBody = t.TypeOf; -export const BulkDeleteRulesRequestBody = t.array(QueryRuleByIds); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.gen.ts new file mode 100644 index 00000000000000..645e0e77a6de4e --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.gen.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RulePatchProps } from '../../../model/rule_schema/rule_schemas.gen'; +import { BulkCrudRulesResponse } from '../response_schema.gen'; + +export type BulkPatchRulesRequestBody = z.infer; +export const BulkPatchRulesRequestBody = z.array(RulePatchProps); +export type BulkPatchRulesRequestBodyInput = z.input; + +export type BulkPatchRulesResponse = z.infer; +export const BulkPatchRulesResponse = BulkCrudRulesResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml index cbb3b4555a419c..eb4ea8a06fc808 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.schema.yaml @@ -5,8 +5,8 @@ info: paths: /api/detection_engine/rules/_bulk_update: patch: - operationId: PatchRulesBulk - x-codegen-enabled: false + operationId: BulkPatchRules + x-codegen-enabled: true deprecated: true description: Updates multiple rules using the `PATCH` method. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.test.ts index 9e1351c7f25f02..443a3e0862b45a 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.test.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { exactCheck, formatErrors, foldLeftRight } from '@kbn/securitysolution-io-ts-utils'; -import type { PatchRuleRequestBody } from '../../crud/patch_rule/patch_rule_route'; -import { BulkPatchRulesRequestBody } from './bulk_patch_rules_route'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; +import type { PatchRuleRequestBody } from '../../crud/patch_rule/patch_rule_route.gen'; +import { BulkPatchRulesRequestBody } from './bulk_patch_rules_route.gen'; // only the basics of testing are here. // see: patch_rules_schema.test.ts for the bulk of the validation tests @@ -16,21 +16,17 @@ describe('Bulk patch rules request schema', () => { test('can take an empty array and validate it', () => { const payload: BulkPatchRulesRequestBody = []; - const decoded = BulkPatchRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(output.errors).toEqual([]); - expect(output.schema).toEqual([]); + const result = BulkPatchRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('single array of [id] does validate', () => { const payload: BulkPatchRulesRequestBody = [{ id: '4125761e-51da-4de9-a0c8-42824f532ddb' }]; - const decoded = BulkPatchRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkPatchRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('two arrays of [id] validate', () => { @@ -39,11 +35,9 @@ describe('Bulk patch rules request schema', () => { { id: '192f403d-b285-4251-9e8b-785fcfcf22e8' }, ]; - const decoded = BulkPatchRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkPatchRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('can set "note" to be a string', () => { @@ -52,11 +46,9 @@ describe('Bulk patch rules request schema', () => { { note: 'hi' }, ]; - const decoded = BulkPatchRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkPatchRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('can set "note" to be an empty string', () => { @@ -65,11 +57,9 @@ describe('Bulk patch rules request schema', () => { { note: '' }, ]; - const decoded = BulkPatchRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkPatchRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('cannot set "note" to be anything other than a string', () => { @@ -78,12 +68,8 @@ describe('Bulk patch rules request schema', () => { { note: { someprop: 'some value here' } }, ]; - const decoded = BulkPatchRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "{"someprop":"some value here"}" supplied to "note"', - ]); - expect(output.schema).toEqual({}); + const result = BulkPatchRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"1: Invalid input"`); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.ts deleted file mode 100644 index c2980211c7fad3..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_patch_rules/bulk_patch_rules_route.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { RulePatchProps } from '../../../model'; - -/** - * Request body parameters of the API route. - */ -export type BulkPatchRulesRequestBody = t.TypeOf; -export const BulkPatchRulesRequestBody = t.array(RulePatchProps); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.gen.ts new file mode 100644 index 00000000000000..82095c408fa7eb --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.gen.ts @@ -0,0 +1,23 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleUpdateProps } from '../../../model/rule_schema/rule_schemas.gen'; +import { BulkCrudRulesResponse } from '../response_schema.gen'; + +export type BulkUpdateRulesRequestBody = z.infer; +export const BulkUpdateRulesRequestBody = z.array(RuleUpdateProps); +export type BulkUpdateRulesRequestBodyInput = z.input; + +export type BulkUpdateRulesResponse = z.infer; +export const BulkUpdateRulesResponse = BulkCrudRulesResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml index 56bf7fe2f8d062..5259a677bc1f09 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.schema.yaml @@ -5,8 +5,8 @@ info: paths: /api/detection_engine/rules/_bulk_update: put: - operationId: UpdateRulesBulk - x-codegen-enabled: false + operationId: BulkUpdateRules + x-codegen-enabled: true deprecated: true description: Updates multiple rules using the `PUT` method. tags: diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts index 46dbbd22b7aaae..86a3a943b6626c 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.test.ts @@ -5,10 +5,10 @@ * 2.0. */ -import { exactCheck, formatErrors, foldLeftRight } from '@kbn/securitysolution-io-ts-utils'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import type { RuleUpdateProps } from '../../../model'; import { getUpdateRulesSchemaMock } from '../../../model/rule_schema/mocks'; -import { BulkUpdateRulesRequestBody } from './bulk_update_rules_route'; +import { BulkUpdateRulesRequestBody } from './bulk_update_rules_route.gen'; // only the basics of testing are here. // see: update_rules_schema.test.ts for the bulk of the validation tests @@ -17,40 +17,25 @@ describe('Bulk update rules request schema', () => { test('can take an empty array and validate it', () => { const payload: BulkUpdateRulesRequestBody = []; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(output.errors).toEqual([]); - expect(output.schema).toEqual([]); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('made up values do not validate for a single element', () => { const payload: Array<{ madeUp: string }> = [{ madeUp: 'hi' }]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toContain( - 'Invalid value "undefined" supplied to "description"' - ); - expect(formatErrors(output.errors)).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(formatErrors(output.errors)).toContain('Invalid value "undefined" supplied to "name"'); - expect(formatErrors(output.errors)).toContain( - 'Invalid value "undefined" supplied to "severity"' - ); - expect(output.schema).toEqual({}); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('single array element does validate', () => { const payload: BulkUpdateRulesRequestBody = [getUpdateRulesSchemaMock()]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('two array elements do validate', () => { @@ -59,11 +44,9 @@ describe('Bulk update rules request schema', () => { getUpdateRulesSchemaMock(), ]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('single array element with a missing value (risk_score) will not validate', () => { @@ -72,13 +55,9 @@ describe('Bulk update rules request schema', () => { delete singleItem.risk_score; const payload: BulkUpdateRulesRequestBody = [singleItem]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(output.schema).toEqual({}); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('two array elements where the first is valid but the second is invalid (risk_score) will not validate', () => { @@ -88,13 +67,9 @@ describe('Bulk update rules request schema', () => { delete secondItem.risk_score; const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(output.schema).toEqual({}); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"1: Invalid input"`); }); test('two array elements where the first is invalid (risk_score) but the second is valid will not validate', () => { @@ -104,13 +79,9 @@ describe('Bulk update rules request schema', () => { delete singleItem.risk_score; const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(output.schema).toEqual({}); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('two array elements where both are invalid (risk_score) will not validate', () => { @@ -122,46 +93,14 @@ describe('Bulk update rules request schema', () => { delete secondItem.risk_score; const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - ]); - expect(output.schema).toEqual({}); - }); - - test('two array elements where the first is invalid (extra key and value) but the second is valid will not validate', () => { - const singleItem: RuleUpdateProps & { madeUpValue: string } = { - ...getUpdateRulesSchemaMock(), - madeUpValue: 'something', - }; - const secondItem = getUpdateRulesSchemaMock(); - const payload = [singleItem, secondItem]; - - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue"']); - expect(output.schema).toEqual({}); - }); - - test('two array elements where the second is invalid (extra key and value) but the first is valid will not validate', () => { - const singleItem: RuleUpdateProps = getUpdateRulesSchemaMock(); - const secondItem: RuleUpdateProps & { madeUpValue: string } = { - ...getUpdateRulesSchemaMock(), - madeUpValue: 'something', - }; - const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue"']); - expect(output.schema).toEqual({}); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"0: Invalid input, 1: Invalid input"` + ); }); - test('two array elements where both are invalid (extra key and value) will not validate', () => { + test('extra props will be omitted from the payload after validation', () => { const singleItem: RuleUpdateProps & { madeUpValue: string } = { ...getUpdateRulesSchemaMock(), madeUpValue: 'something', @@ -172,22 +111,18 @@ describe('Bulk update rules request schema', () => { }; const payload: BulkUpdateRulesRequestBody = [singleItem, secondItem]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['invalid keys "madeUpValue,madeUpValue"']); - expect(output.schema).toEqual({}); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual([getUpdateRulesSchemaMock(), getUpdateRulesSchemaMock()]); }); test('You cannot set the severity to a value other than low, medium, high, or critical', () => { const badSeverity = { ...getUpdateRulesSchemaMock(), severity: 'madeup' }; const payload = [badSeverity]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual(['Invalid value "madeup" supplied to "severity"']); - expect(output.schema).toEqual({}); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('You can set "namespace" to a string', () => { @@ -195,11 +130,9 @@ describe('Bulk update rules request schema', () => { { ...getUpdateRulesSchemaMock(), namespace: 'a namespace' }, ]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set "note" to a string', () => { @@ -207,21 +140,17 @@ describe('Bulk update rules request schema', () => { { ...getUpdateRulesSchemaMock(), note: '# test markdown' }, ]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set "note" to an empty string', () => { const payload: BulkUpdateRulesRequestBody = [{ ...getUpdateRulesSchemaMock(), note: '' }]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([]); - expect(output.schema).toEqual(payload); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cant set "note" to anything other than string', () => { @@ -234,12 +163,8 @@ describe('Bulk update rules request schema', () => { }, ]; - const decoded = BulkUpdateRulesRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const output = foldLeftRight(checked); - expect(formatErrors(output.errors)).toEqual([ - 'Invalid value "{"something":"some object"}" supplied to "note"', - ]); - expect(output.schema).toEqual({}); + const result = BulkUpdateRulesRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.ts deleted file mode 100644 index 649898adc9e371..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/bulk_update_rules/bulk_update_rules_route.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { RuleUpdateProps } from '../../../model'; - -/** - * Request body parameters of the API route. - */ -export type BulkUpdateRulesRequestBody = t.TypeOf; -export const BulkUpdateRulesRequestBody = t.array(RuleUpdateProps); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.gen.ts new file mode 100644 index 00000000000000..b105bd00d94c33 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.gen.ts @@ -0,0 +1,19 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleResponse } from '../../model/rule_schema/rule_schemas.gen'; +import { ErrorSchema } from '../../model/error_schema.gen'; + +export type BulkCrudRulesResponse = z.infer; +export const BulkCrudRulesResponse = z.array(z.union([RuleResponse, ErrorSchema])); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.schema.yaml index b30ac7135c64df..30eedb8859c1f4 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.schema.yaml @@ -4,7 +4,7 @@ info: version: 8.9.0 paths: {} components: - x-codegen-enabled: false + x-codegen-enabled: true schemas: BulkCrudRulesResponse: type: array diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts index ba6020369f1691..d8e3c997e22790 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/bulk_crud/response_schema.test.ts @@ -5,45 +5,36 @@ * 2.0. */ -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - -import type { RuleResponse, ErrorSchema } from '../../model'; -import { getRulesSchemaMock } from '../../model/rule_schema/mocks'; +import type { ErrorSchema, RuleResponse } from '../../model'; import { getErrorSchemaMock } from '../../model/error_schema.mock'; +import { getRulesSchemaMock } from '../../model/rule_schema/mocks'; -import { BulkCrudRulesResponse } from './response_schema'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; +import { BulkCrudRulesResponse } from './response_schema.gen'; describe('Bulk CRUD rules response schema', () => { test('it should validate a regular message and and error together with a uuid', () => { const payload: BulkCrudRulesResponse = [getRulesSchemaMock(), getErrorSchemaMock()]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([getRulesSchemaMock(), getErrorSchemaMock()]); + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); - test('it should validate a regular message and and error together when the error has a non UUID', () => { + test('it should validate a regular message and error together when the error has a non UUID', () => { const payload: BulkCrudRulesResponse = [getRulesSchemaMock(), getErrorSchemaMock('fake id')]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([getRulesSchemaMock(), getErrorSchemaMock('fake id')]); + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should validate an error', () => { const payload: BulkCrudRulesResponse = [getErrorSchemaMock('fake id')]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual([getErrorSchemaMock('fake id')]); + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('it should NOT validate a rule with a deleted value', () => { @@ -51,15 +42,10 @@ describe('Bulk CRUD rules response schema', () => { // @ts-expect-error delete rule.name; const payload: BulkCrudRulesResponse = [rule]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "name"', - 'Invalid value "undefined" supplied to "error"', - ]); - expect(message.schema).toEqual({}); + + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); test('it should NOT validate an invalid error message with a deleted value', () => { @@ -67,38 +53,30 @@ describe('Bulk CRUD rules response schema', () => { // @ts-expect-error delete error.error; const payload: BulkCrudRulesResponse = [error]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "error"' - ); - expect(message.schema).toEqual({}); + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"0: Invalid input"`); }); - test('it should NOT validate a type of "query" when it has extra data', () => { + test('it should omit any extra rule props', () => { const rule: RuleResponse & { invalid_extra_data?: string } = getRulesSchemaMock(); rule.invalid_extra_data = 'invalid_extra_data'; const payload: BulkCrudRulesResponse = [rule]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']); - expect(message.schema).toEqual({}); + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual([getRulesSchemaMock()]); }); test('it should NOT validate a type of "query" when it has extra data next to a valid error', () => { const rule: RuleResponse & { invalid_extra_data?: string } = getRulesSchemaMock(); rule.invalid_extra_data = 'invalid_extra_data'; const payload: BulkCrudRulesResponse = [getErrorSchemaMock(), rule]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']); - expect(message.schema).toEqual({}); + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual([getErrorSchemaMock(), getRulesSchemaMock()]); }); test('it should NOT validate an error when it has extra data', () => { @@ -106,12 +84,12 @@ describe('Bulk CRUD rules response schema', () => { const error: InvalidError = getErrorSchemaMock(); error.invalid_extra_data = 'invalid'; const payload: BulkCrudRulesResponse = [error]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']); - expect(message.schema).toEqual({}); + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"0: Unrecognized key(s) in object: 'invalid_extra_data'"` + ); }); test('it should NOT validate an error when it has extra data next to a valid payload element', () => { @@ -119,11 +97,11 @@ describe('Bulk CRUD rules response schema', () => { const error: InvalidError = getErrorSchemaMock(); error.invalid_extra_data = 'invalid'; const payload: BulkCrudRulesResponse = [getRulesSchemaMock(), error]; - const decoded = BulkCrudRulesResponse.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "invalid_extra_data"']); - expect(message.schema).toEqual({}); + const result = BulkCrudRulesResponse.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"1: Unrecognized key(s) in object: 'invalid_extra_data'"` + ); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.gen.ts new file mode 100644 index 00000000000000..ff0832a86f320a --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.gen.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleCreateProps, RuleResponse } from '../../../model/rule_schema/rule_schemas.gen'; + +export type CreateRuleRequestBody = z.infer; +export const CreateRuleRequestBody = RuleCreateProps; +export type CreateRuleRequestBodyInput = z.input; + +export type CreateRuleResponse = z.infer; +export const CreateRuleResponse = RuleResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml index 12b92c026ef000..f3e49fc95a0484 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.schema.yaml @@ -6,7 +6,7 @@ paths: /api/detection_engine/rules: post: operationId: CreateRule - x-codegen-enabled: false + x-codegen-enabled: true description: Create a single detection rule tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.ts deleted file mode 100644 index 164c6cfb1a93cd..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/create_rule/create_rule_route.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as t from 'io-ts'; -import { RuleCreateProps, RuleResponse } from '../../../model'; - -export const CreateRuleRequestBody = RuleCreateProps; -export type CreateRuleRequestBody = t.TypeOf; - -export const CreateRuleResponse = RuleResponse; -export type CreateRuleResponse = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.gen.ts new file mode 100644 index 00000000000000..b885a8dd64a46a --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.gen.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleObjectId, RuleSignatureId } from '../../../model/rule_schema/common_attributes.gen'; +import { RuleResponse } from '../../../model/rule_schema/rule_schemas.gen'; + +export type DeleteRuleRequestQuery = z.infer; +export const DeleteRuleRequestQuery = z.object({ + /** + * The rule's `id` value. + */ + id: RuleObjectId.optional(), + /** + * The rule's `rule_id` value. + */ + rule_id: RuleSignatureId.optional(), +}); +export type DeleteRuleRequestQueryInput = z.input; + +export type DeleteRuleResponse = z.infer; +export const DeleteRuleResponse = RuleResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml index c873ceb1417706..66236f70b9b6c5 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.schema.yaml @@ -6,7 +6,7 @@ paths: /api/detection_engine/rules: delete: operationId: DeleteRule - x-codegen-enabled: false + x-codegen-enabled: true description: Deletes a single rule using the `rule_id` or `id` field. tags: - Rules API @@ -16,13 +16,13 @@ paths: required: false description: The rule's `id` value. schema: - $ref: '../../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleSignatureId' + $ref: '../../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleObjectId' - name: rule_id in: query required: false description: The rule's `rule_id` value. schema: - $ref: '../../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleObjectId' + $ref: '../../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleSignatureId' responses: 200: description: Indicates a successful call. diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.ts deleted file mode 100644 index 78a3423182b8dc..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/delete_rule/delete_rule_route.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as t from 'io-ts'; -import { RuleResponse } from '../../../model'; -import { QueryRuleByIds } from '../../model/query_rule_by_ids'; - -export const DeleteRuleRequestQuery = QueryRuleByIds; -export type DeleteRuleRequestQuery = t.TypeOf; - -export const DeleteRuleResponse = RuleResponse; -export type DeleteRuleResponse = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.gen.ts new file mode 100644 index 00000000000000..840de35ccf5ca8 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.gen.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RulePatchProps, RuleResponse } from '../../../model/rule_schema/rule_schemas.gen'; + +export type PatchRuleRequestBody = z.infer; +export const PatchRuleRequestBody = RulePatchProps; +export type PatchRuleRequestBodyInput = z.input; + +export type PatchRuleResponse = z.infer; +export const PatchRuleResponse = RuleResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.mock.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.mock.ts index 7f2645c15e46da..62fba4c3212238 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.mock.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.mock.ts @@ -6,7 +6,7 @@ */ import type { ThresholdRulePatchProps } from '../../../model'; -import type { PatchRuleRequestBody } from './patch_rule_route'; +import type { PatchRuleRequestBody } from './patch_rule_route.gen'; export const getPatchRulesSchemaMock = (): PatchRuleRequestBody => ({ description: 'some description', diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml index 1883b90c46cbe8..98a76e3712b45a 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.schema.yaml @@ -6,7 +6,7 @@ paths: /api/detection_engine/rules: patch: operationId: PatchRule - x-codegen-enabled: false + x-codegen-enabled: true description: Patch a single rule tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.test.ts index 902b5d0c508996..b70b5a6a7d9084 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.test.ts @@ -5,12 +5,9 @@ * 2.0. */ -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { getListArrayMock } from '../../../../../detection_engine/schemas/types/lists.mock'; -import { PatchRuleRequestBody } from './patch_rule_route'; +import { PatchRuleRequestBody } from './patch_rule_route.gen'; import { getPatchRulesSchemaMock } from './patch_rule_route.mock'; describe('Patch rule request schema', () => { @@ -19,14 +16,9 @@ describe('Patch rule request schema', () => { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id] does validate', () => { @@ -34,14 +26,9 @@ describe('Patch rule request schema', () => { rule_id: 'rule-1', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description] does validate', () => { @@ -50,15 +37,9 @@ describe('Patch rule request schema', () => { description: 'some description', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, description] does validate', () => { @@ -67,15 +48,9 @@ describe('Patch rule request schema', () => { description: 'some description', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, risk_score] does validate', () => { @@ -84,15 +59,9 @@ describe('Patch rule request schema', () => { risk_score: 10, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - risk_score: 10, - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from] does validate', () => { @@ -102,16 +71,9 @@ describe('Patch rule request schema', () => { from: 'now-5m', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to] does validate', () => { @@ -122,17 +84,9 @@ describe('Patch rule request schema', () => { to: 'now', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, description, from, to] does validate', () => { @@ -143,17 +97,9 @@ describe('Patch rule request schema', () => { to: 'now', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - from: 'now-5m', - to: 'now', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, name] does validate', () => { @@ -165,18 +111,9 @@ describe('Patch rule request schema', () => { name: 'some-name', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, description, from, to, name] does validate', () => { @@ -188,18 +125,9 @@ describe('Patch rule request schema', () => { name: 'some-name', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, name, severity] does validate', () => { @@ -212,19 +140,9 @@ describe('Patch rule request schema', () => { severity: 'low', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, description, from, to, name, severity] does validate', () => { @@ -237,19 +155,9 @@ describe('Patch rule request schema', () => { severity: 'low', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, name, severity, type] does validate', () => { @@ -263,20 +171,9 @@ describe('Patch rule request schema', () => { type: 'query', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - type: 'query', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, description, from, to, name, severity, type] does validate', () => { @@ -290,20 +187,9 @@ describe('Patch rule request schema', () => { type: 'query', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - type: 'query', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, name, severity, type, interval] does validate', () => { @@ -318,21 +204,9 @@ describe('Patch rule request schema', () => { type: 'query', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, description, from, to, name, severity, type, interval] does validate', () => { @@ -347,21 +221,9 @@ describe('Patch rule request schema', () => { type: 'query', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, query] does validate', () => { @@ -378,23 +240,9 @@ describe('Patch rule request schema', () => { query: 'some query', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - query: 'some query', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, description, from, to, index, name, severity, interval, type, query, language] does validate', () => { @@ -411,23 +259,9 @@ describe('Patch rule request schema', () => { language: 'kuery', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - query: 'some query', - language: 'kuery', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does validate', () => { @@ -439,18 +273,9 @@ describe('Patch rule request schema', () => { name: 'some-name', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[id, description, from, to, index, name, severity, type, filters] does validate', () => { @@ -466,22 +291,9 @@ describe('Patch rule request schema', () => { filters: [], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - filters: [], - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, type, filters] does validate', () => { @@ -497,22 +309,9 @@ describe('Patch rule request schema', () => { filters: [], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - filters: [], - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('allows references to be sent as a valid value to patch with', () => { @@ -531,25 +330,9 @@ describe('Patch rule request schema', () => { language: 'kuery', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - references: ['index-1'], - query: 'some query', - language: 'kuery', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('does not default references to an array', () => { @@ -557,11 +340,9 @@ describe('Patch rule request schema', () => { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as PatchRuleRequestBody).references).toEqual(undefined); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data.references).toEqual(undefined); }); test('does not default interval', () => { @@ -569,11 +350,9 @@ describe('Patch rule request schema', () => { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as PatchRuleRequestBody).interval).toEqual(undefined); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data.interval).toEqual(undefined); }); test('does not default max_signals', () => { @@ -581,11 +360,9 @@ describe('Patch rule request schema', () => { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as PatchRuleRequestBody).max_signals).toEqual(undefined); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data.max_signals).toEqual(undefined); }); test('references cannot be numbers', () => { @@ -594,11 +371,9 @@ describe('Patch rule request schema', () => { references: [5], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "references"']); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('indexes cannot be numbers', () => { @@ -608,14 +383,9 @@ describe('Patch rule request schema', () => { index: [5], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "query" supplied to "type"', - 'Invalid value "5" supplied to "index"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('saved_id is not required when type is saved_query and will validate without it', () => { @@ -624,15 +394,9 @@ describe('Patch rule request schema', () => { type: 'saved_query', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', - type: 'saved_query', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('saved_id validates with type:saved_query', () => { @@ -642,16 +406,9 @@ describe('Patch rule request schema', () => { saved_id: 'some id', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = { - ...getPatchRulesSchemaMock(), - type: 'saved_query', - saved_id: 'some id', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('saved_query type can have filters with it', () => { @@ -661,16 +418,9 @@ describe('Patch rule request schema', () => { filters: [], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = { - ...getPatchRulesSchemaMock(), - saved_id: 'some id', - filters: [], - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('language validates with kuery', () => { @@ -680,16 +430,9 @@ describe('Patch rule request schema', () => { language: 'kuery', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = { - ...getPatchRulesSchemaMock(), - query: 'some query', - language: 'kuery', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('language validates with lucene', () => { @@ -699,17 +442,9 @@ describe('Patch rule request schema', () => { language: 'lucene', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - - const expected = { - ...getPatchRulesSchemaMock(), - query: 'some query', - language: 'lucene', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('language does not validate with something made up', () => { @@ -719,13 +454,9 @@ describe('Patch rule request schema', () => { language: 'something-made-up', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "something-made-up" supplied to "language"' - ); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('max_signals cannot be negative', () => { @@ -735,13 +466,11 @@ describe('Patch rule request schema', () => { max_signals: -1, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "max_signals"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"max_signals: Number must be greater than or equal to 1"` + ); }); test('max_signals cannot be zero', () => { @@ -751,11 +480,11 @@ describe('Patch rule request schema', () => { max_signals: 0, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "0" supplied to "max_signals"']); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"max_signals: Number must be greater than or equal to 1"` + ); }); test('max_signals can be 1', () => { @@ -765,16 +494,9 @@ describe('Patch rule request schema', () => { max_signals: 1, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected = { - ...getPatchRulesSchemaMock(), - query: 'some query', - max_signals: 1, - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('meta can be patched', () => { @@ -783,15 +505,9 @@ describe('Patch rule request schema', () => { meta: { whateverYouWant: 'anything_at_all' }, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - ...getPatchRulesSchemaMock(), - meta: { whateverYouWant: 'anything_at_all' }, - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot patch meta as a string', () => { @@ -800,13 +516,9 @@ describe('Patch rule request schema', () => { meta: 'should not work', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "should not work" supplied to "meta"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('filters cannot be a string', () => { @@ -815,13 +527,9 @@ describe('Patch rule request schema', () => { filters: 'should not work', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "should not work" supplied to "filters"' - ); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('name cannot be an empty string', () => { @@ -830,11 +538,11 @@ describe('Patch rule request schema', () => { name: '', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "name"']); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"name: String must contain at least 1 character(s)"` + ); }); test('description cannot be an empty string', () => { @@ -843,11 +551,11 @@ describe('Patch rule request schema', () => { description: '', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "" supplied to "description"']); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"description: String must contain at least 1 character(s)"` + ); }); test('threat is not defaulted to empty array on patch', () => { @@ -855,11 +563,9 @@ describe('Patch rule request schema', () => { id: 'b8f95e17-681f-407f-8a5e-b832a77d3831', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as PatchRuleRequestBody).threat).toEqual(undefined); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data.threat).toEqual(undefined); }); test('threat is not defaulted to undefined on patch with empty array', () => { @@ -868,11 +574,9 @@ describe('Patch rule request schema', () => { threat: [], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect((message.schema as PatchRuleRequestBody).threat).toEqual([]); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data.threat).toEqual([]); }); test('threat is valid when updated with all sub-objects', () => { @@ -898,11 +602,9 @@ describe('Patch rule request schema', () => { threat, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('threat is invalid when updated with missing property framework', () => { @@ -927,13 +629,9 @@ describe('Patch rule request schema', () => { threat, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "threat,framework"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('threat is invalid when updated with missing tactic sub-object', () => { @@ -955,13 +653,9 @@ describe('Patch rule request schema', () => { threat, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "threat,tactic"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('threat is valid when updated with missing technique', () => { @@ -981,11 +675,9 @@ describe('Patch rule request schema', () => { threat, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual(payload); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('validates with timeline_id and timeline_title', () => { @@ -995,16 +687,9 @@ describe('Patch rule request schema', () => { timeline_title: 'some-title', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - ...getPatchRulesSchemaMock(), - timeline_id: 'some-id', - timeline_title: 'some-title', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot set the severity to a value other than low, medium, high, or critical', () => { @@ -1013,11 +698,9 @@ describe('Patch rule request schema', () => { severity: 'junk', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "junk" supplied to "severity"']); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); describe('note', () => { @@ -1035,23 +718,9 @@ describe('Patch rule request schema', () => { note: '# some documentation markdown', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - note: '# some documentation markdown', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('note can be patched', () => { @@ -1060,15 +729,9 @@ describe('Patch rule request schema', () => { note: '# new documentation markdown', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - note: '# new documentation markdown', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot patch note as an object', () => { @@ -1079,13 +742,9 @@ describe('Patch rule request schema', () => { }, }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "{"someProperty":"something else here"}" supplied to "note"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); }); @@ -1095,13 +754,9 @@ describe('Patch rule request schema', () => { actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,group"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('You cannot send in an array of actions that are missing "id"', () => { @@ -1110,13 +765,9 @@ describe('Patch rule request schema', () => { actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,id"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('You cannot send in an array of actions that are missing "params"', () => { @@ -1125,13 +776,9 @@ describe('Patch rule request schema', () => { actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,params"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('You cannot send in an array of actions that are including "actionTypeId"', () => { @@ -1147,13 +794,9 @@ describe('Patch rule request schema', () => { ], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,action_type_id"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); describe('exception_list', () => { @@ -1173,38 +816,9 @@ describe('Patch rule request schema', () => { exceptions_list: getListArrayMock(), }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - filters: [], - note: '# some documentation markdown', - exceptions_list: [ - { - id: 'some_uuid', - list_id: 'list_id_single', - namespace_type: 'single', - type: 'detection', - }, - { - id: 'endpoint_list', - list_id: 'endpoint_list', - namespace_type: 'agnostic', - type: 'endpoint', - }, - ], - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, and empty exceptions_list] does validate', () => { @@ -1224,26 +838,9 @@ describe('Patch rule request schema', () => { exceptions_list: [], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - filters: [], - risk_score: 50, - note: '# some markdown', - exceptions_list: [], - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, and invalid exceptions_list] does NOT validate', () => { @@ -1263,15 +860,9 @@ describe('Patch rule request schema', () => { exceptions_list: [{ id: 'uuid_here', namespace_type: 'not a namespace type' }], }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "exceptions_list,list_id"', - 'Invalid value "undefined" supplied to "exceptions_list,type"', - 'Invalid value "not a namespace type" supplied to "exceptions_list,namespace_type"', - ]); - expect(message.schema).toEqual({}); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, and non-existent exceptions_list] does validate with empty exceptions_list', () => { @@ -1290,25 +881,9 @@ describe('Patch rule request schema', () => { note: '# some markdown', }; - const decoded = PatchRuleRequestBody.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - const expected: PatchRuleRequestBody = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - filters: [], - risk_score: 50, - note: '# some markdown', - }; - expect(message.schema).toEqual(expected); + const result = PatchRuleRequestBody.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.ts deleted file mode 100644 index 01ef956bc4b433..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/patch_rule_route.ts +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as t from 'io-ts'; -import { RulePatchProps, RuleResponse } from '../../../model'; - -/** - * Request body parameters of the API route. - * All of the patch elements should default to undefined if not set. - */ -export type PatchRuleRequestBody = RulePatchProps; -export const PatchRuleRequestBody = RulePatchProps; - -export const PatchRuleResponse = RuleResponse; -export type PatchRuleResponse = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/request_schema_validation.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/request_schema_validation.test.ts index 3e1a9da5cdc6e8..5a60a3331a2ae0 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/request_schema_validation.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/request_schema_validation.test.ts @@ -6,7 +6,7 @@ */ import type { ThresholdRulePatchProps } from '../../../model'; -import type { PatchRuleRequestBody } from './patch_rule_route'; +import type { PatchRuleRequestBody } from './patch_rule_route.gen'; import { getPatchRulesSchemaMock, getPatchThresholdRulesSchemaMock } from './patch_rule_route.mock'; import { validatePatchRuleRequestBody } from './request_schema_validation'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/request_schema_validation.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/request_schema_validation.ts index f27237b563b216..cb34c7fa8ecb53 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/request_schema_validation.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/patch_rule/request_schema_validation.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { PatchRuleRequestBody } from './patch_rule_route'; +import type { PatchRuleRequestBody } from './patch_rule_route.gen'; /** * Additional validation that is implemented outside of the schema itself. diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.gen.ts new file mode 100644 index 00000000000000..1d10fede9bec41 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.gen.ts @@ -0,0 +1,32 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleObjectId, RuleSignatureId } from '../../../model/rule_schema/common_attributes.gen'; +import { RuleResponse } from '../../../model/rule_schema/rule_schemas.gen'; + +export type ReadRuleRequestQuery = z.infer; +export const ReadRuleRequestQuery = z.object({ + /** + * The rule's `id` value. + */ + id: RuleObjectId.optional(), + /** + * The rule's `rule_id` value. + */ + rule_id: RuleSignatureId.optional(), +}); +export type ReadRuleRequestQueryInput = z.input; + +export type ReadRuleResponse = z.infer; +export const ReadRuleResponse = RuleResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml index 8c5a5accb2c769..8713e295e8f33d 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.schema.yaml @@ -6,7 +6,7 @@ paths: /api/detection_engine/rules: get: operationId: ReadRule - x-codegen-enabled: false + x-codegen-enabled: true description: Read a single rule tags: - Rules API @@ -16,13 +16,13 @@ paths: required: false description: The rule's `id` value. schema: - $ref: '../../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleSignatureId' + $ref: '../../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleObjectId' - name: rule_id in: query required: false description: The rule's `rule_id` value. schema: - $ref: '../../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleObjectId' + $ref: '../../../model/rule_schema/common_attributes.schema.yaml#/components/schemas/RuleSignatureId' responses: 200: description: Indicates a successful call. diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.ts deleted file mode 100644 index 66d31edf785acd..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/read_rule/read_rule_route.ts +++ /dev/null @@ -1,16 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as t from 'io-ts'; -import { RuleResponse } from '../../../model'; -import { QueryRuleByIds } from '../../model/query_rule_by_ids'; - -export const ReadRuleRequestQuery = QueryRuleByIds; -export type ReadRuleRequestQuery = t.TypeOf; - -export const ReadRuleResponse = RuleResponse; -export type ReadRuleResponse = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.gen.ts new file mode 100644 index 00000000000000..7b539471707987 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.gen.ts @@ -0,0 +1,22 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import type { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleUpdateProps, RuleResponse } from '../../../model/rule_schema/rule_schemas.gen'; + +export type UpdateRuleRequestBody = z.infer; +export const UpdateRuleRequestBody = RuleUpdateProps; +export type UpdateRuleRequestBodyInput = z.input; + +export type UpdateRuleResponse = z.infer; +export const UpdateRuleResponse = RuleResponse; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml index e969cf13ecf276..7adaca37a243b3 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.schema.yaml @@ -6,7 +6,7 @@ paths: /api/detection_engine/rules: put: operationId: UpdateRule - x-codegen-enabled: false + x-codegen-enabled: true description: Update a single rule tags: - Rules API diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.ts deleted file mode 100644 index 0b695f6c3c0210..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/crud/update_rule/update_rule_route.ts +++ /dev/null @@ -1,15 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type * as t from 'io-ts'; -import { RuleResponse, RuleUpdateProps } from '../../../model'; - -export const UpdateRuleRequestBody = RuleUpdateProps; -export type UpdateRuleRequestBody = t.TypeOf; - -export const UpdateRuleResponse = RuleResponse; -export type UpdateRuleResponse = t.TypeOf; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.test.ts index 2ec18f7f86c8b7..49b56c66732185 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/export_rules/export_rules_route.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { stringifyZodError } from '@kbn/securitysolution-es-utils'; -import { expectParseError, expectParseSuccess } from '../../../../test/zod_helpers'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import type { ExportRulesRequestQueryInput } from './export_rules_route.gen'; import { ExportRulesRequestBody, ExportRulesRequestQuery } from './export_rules_route.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.test.ts index 56fcece0f122ac..e868d050ecfe18 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/import_rules_route.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { stringifyZodError } from '@kbn/securitysolution-es-utils'; -import { expectParseError, expectParseSuccess } from '../../../../test/zod_helpers'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import type { ErrorSchema } from '../../model/error_schema.gen'; import { ImportRulesResponse } from './import_rules_route.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.ts index 1b01d913eaee2d..d494461d2cdb1e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/import_rules/rule_to_import.ts @@ -8,6 +8,8 @@ import * as t from 'io-ts'; import { OnlyFalseAllowed } from '@kbn/securitysolution-io-ts-types'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports import { RelatedIntegrationArray, RequiredFieldArray, @@ -16,12 +18,8 @@ import { SetupGuide, BaseCreateProps, TypeSpecificCreateProps, - created_at, - updated_at, - created_by, - updated_by, - revision, -} from '../../model'; +} from '../../model/rule_schema_legacy'; +import { created_at, updated_at, created_by, updated_by, revision } from '../../model'; /** * Differences from this and the createRulesSchema are diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/index.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/index.ts index a9100970ca7537..7fdab0816d650f 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/index.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/index.ts @@ -6,20 +6,20 @@ */ export * from './bulk_actions/bulk_actions_route'; -export * from './bulk_crud/bulk_create_rules/bulk_create_rules_route'; -export * from './bulk_crud/bulk_delete_rules/bulk_delete_rules_route'; -export * from './bulk_crud/bulk_patch_rules/bulk_patch_rules_route'; -export * from './bulk_crud/bulk_update_rules/bulk_update_rules_route'; -export * from './bulk_crud/response_schema'; +export * from './bulk_crud/bulk_create_rules/bulk_create_rules_route.gen'; +export * from './bulk_crud/bulk_delete_rules/bulk_delete_rules_route.gen'; +export * from './bulk_crud/bulk_patch_rules/bulk_patch_rules_route.gen'; +export * from './bulk_crud/bulk_update_rules/bulk_update_rules_route.gen'; +export * from './bulk_crud/response_schema.gen'; export * from './coverage_overview/coverage_overview_route'; -export * from './crud/create_rule/create_rule_route'; +export * from './crud/create_rule/create_rule_route.gen'; export * from './crud/create_rule/request_schema_validation'; -export * from './crud/delete_rule/delete_rule_route'; -export * from './crud/patch_rule/patch_rule_route'; +export * from './crud/delete_rule/delete_rule_route.gen'; +export * from './crud/patch_rule/patch_rule_route.gen'; export * from './crud/patch_rule/request_schema_validation'; -export * from './crud/read_rule/read_rule_route'; +export * from './crud/read_rule/read_rule_route.gen'; export * from './crud/update_rule/request_schema_validation'; -export * from './crud/update_rule/update_rule_route'; +export * from './crud/update_rule/update_rule_route.gen'; export * from './export_rules/export_rules_details_schema'; export * from './export_rules/export_rules_route.gen'; export * from './find_rules/find_rules_route'; @@ -29,6 +29,5 @@ export * from './import_rules/import_rules_route.gen'; export * from './import_rules/rule_to_import_validation'; export * from './import_rules/rule_to_import'; export * from './model/query_rule_by_ids_validation'; -export * from './model/query_rule_by_ids'; -export * from './urls'; export * from './read_tags/read_tags_route.gen'; +export * from './urls'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids.test.ts deleted file mode 100644 index d5ba9b37ae65a2..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids.test.ts +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; -import { QueryRuleByIds } from './query_rule_by_ids'; - -describe('Query rule by IDs schema', () => { - test('empty objects do validate', () => { - const payload: Partial = {}; - - const decoded = QueryRuleByIds.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - expect(message.schema).toEqual({}); - }); -}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids.ts deleted file mode 100644 index 2de0116d2875f8..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids.ts +++ /dev/null @@ -1,17 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { RuleObjectId, RuleSignatureId } from '../../model'; - -export type QueryRuleByIds = t.TypeOf; -export const QueryRuleByIds = t.exact( - t.partial({ - rule_id: RuleSignatureId, - id: RuleObjectId, - }) -); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids_validation.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids_validation.test.ts index 1d0981df5f4112..d0c107abeb7260 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids_validation.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids_validation.test.ts @@ -5,22 +5,19 @@ * 2.0. */ -import type { QueryRuleByIds } from './query_rule_by_ids'; import { validateQueryRuleByIds } from './query_rule_by_ids_validation'; describe('Query rule by IDs schema, additional validation', () => { test('You cannot have both an id and a rule_id', () => { - const schema: QueryRuleByIds = { + const errors = validateQueryRuleByIds({ id: 'some-id', rule_id: 'some-rule-id', - }; - const errors = validateQueryRuleByIds(schema); + }); expect(errors).toEqual(['both "id" and "rule_id" cannot exist, choose one or the other']); }); test('You must set either an id or a rule_id', () => { - const schema: QueryRuleByIds = {}; - const errors = validateQueryRuleByIds(schema); + const errors = validateQueryRuleByIds({}); expect(errors).toEqual(['either "id" or "rule_id" must be set']); }); }); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids_validation.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids_validation.ts index 2d32cb801ebd93..dfaa14ba6b7f59 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids_validation.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_management/model/query_rule_by_ids_validation.ts @@ -5,12 +5,15 @@ * 2.0. */ -import type { QueryRuleByIds } from './query_rule_by_ids'; +import type { RuleObjectId, RuleSignatureId } from '../../model/rule_schema'; /** * Additional validation that is implemented outside of the schema itself. */ -export const validateQueryRuleByIds = (rule: QueryRuleByIds): string[] => { +export const validateQueryRuleByIds = (rule: { + rule_id?: RuleSignatureId; + id?: RuleObjectId; +}): string[] => { if (rule.id != null && rule.rule_id != null) { return ['both "id" and "rule_id" cannot exist, choose one or the other']; } else if (rule.id == null && rule.rule_id == null) { diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.gen.ts new file mode 100644 index 00000000000000..235437cc5ed68f --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.gen.ts @@ -0,0 +1,30 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +export type RuleExecutionMetrics = z.infer; +export const RuleExecutionMetrics = z.object({ + /** + * Total time spent searching for events + */ + total_search_duration_ms: z.number().int().min(0).optional(), + /** + * Total time spent indexing alerts + */ + total_indexing_duration_ms: z.number().int().min(0).optional(), + total_enrichment_duration_ms: z.number().int().min(0).optional(), + /** + * Time gap between last execution and current execution + */ + execution_gap_duration_s: z.number().int().min(0).optional(), +}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.schema.yaml new file mode 100644 index 00000000000000..7e04ef38a0a875 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_metrics.schema.yaml @@ -0,0 +1,26 @@ +openapi: 3.0.0 +info: + title: Execution Metrics Schema + version: not applicable +paths: {} +components: + x-codegen-enabled: true + schemas: + RuleExecutionMetrics: + type: object + properties: + total_search_duration_ms: + description: Total time spent searching for events + type: integer + minimum: 0 + total_indexing_duration_ms: + description: Total time spent indexing alerts + type: integer + minimum: 0 + total_enrichment_duration_ms: + type: integer + minimum: 0 + execution_gap_duration_s: + description: Time gap between last execution and current execution + type: integer + minimum: 0 diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_result.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_result.gen.ts index 41eab285ac3f08..2d2bbccf531081 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_result.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_result.gen.ts @@ -51,5 +51,5 @@ export const SortFieldOfRuleExecutionResult = z.enum([ 'search_duration_ms', 'schedule_delay_ms', ]); -export const SortFieldOfRuleExecutionResultEnum = SortFieldOfRuleExecutionResult.enum; export type SortFieldOfRuleExecutionResultEnum = typeof SortFieldOfRuleExecutionResult.enum; +export const SortFieldOfRuleExecutionResultEnum = SortFieldOfRuleExecutionResult.enum; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_result.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_result.ts deleted file mode 100644 index 3a15121624b75c..00000000000000 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_result.ts +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import * as t from 'io-ts'; -import { IsoDateString } from '@kbn/securitysolution-io-ts-types'; - -/** - * Rule execution result is an aggregate that groups plain rule execution events by execution UUID. - * It contains such information as execution UUID, date, status and metrics. - */ -export type RuleExecutionResult = t.TypeOf; -export const RuleExecutionResult = t.type({ - execution_uuid: t.string, - timestamp: IsoDateString, - duration_ms: t.number, - status: t.string, - message: t.string, - num_active_alerts: t.number, - num_new_alerts: t.number, - num_recovered_alerts: t.number, - num_triggered_actions: t.number, - num_succeeded_actions: t.number, - num_errored_actions: t.number, - total_search_duration_ms: t.number, - es_search_duration_ms: t.number, - schedule_delay_ms: t.number, - timed_out: t.boolean, - indexing_duration_ms: t.number, - search_duration_ms: t.number, - gap_duration_s: t.number, - security_status: t.string, - security_message: t.string, -}); - -/** - * We support sorting rule execution results by these fields. - */ -export type SortFieldOfRuleExecutionResult = t.TypeOf; -export const SortFieldOfRuleExecutionResult = t.keyof({ - timestamp: IsoDateString, - duration_ms: t.number, - gap_duration_s: t.number, - indexing_duration_ms: t.number, - search_duration_ms: t.number, - schedule_delay_ms: t.number, -}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.gen.ts index 2357e95dae8178..01901971a2a9ba 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.gen.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.gen.ts @@ -28,5 +28,8 @@ export const RuleExecutionStatus = z.enum([ 'failed', 'succeeded', ]); -export const RuleExecutionStatusEnum = RuleExecutionStatus.enum; export type RuleExecutionStatusEnum = typeof RuleExecutionStatus.enum; +export const RuleExecutionStatusEnum = RuleExecutionStatus.enum; + +export type RuleExecutionStatusOrder = z.infer; +export const RuleExecutionStatusOrder = z.number().int(); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.schema.yaml index 7675b217861884..d5ef832547f6a6 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.schema.yaml +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.schema.yaml @@ -22,3 +22,6 @@ components: - partial failure - failed - succeeded + + RuleExecutionStatusOrder: + type: integer diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.ts index c168cdc837fc30..ae031191fd74d9 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_status.ts @@ -6,18 +6,14 @@ */ import type { RuleLastRunOutcomes } from '@kbn/alerting-plugin/common'; -import { enumeration, PositiveInteger } from '@kbn/securitysolution-io-ts-types'; -import type * as t from 'io-ts'; +import { enumeration } from '@kbn/securitysolution-io-ts-types'; import { assertUnreachable } from '../../../../utility_types'; -import type { RuleExecutionStatus } from './execution_status.gen'; +import type { RuleExecutionStatus, RuleExecutionStatusOrder } from './execution_status.gen'; import { RuleExecutionStatusEnum } from './execution_status.gen'; // TODO remove after the migration to Zod is done export const TRuleExecutionStatus = enumeration('RuleExecutionStatus', RuleExecutionStatusEnum); -export type RuleExecutionStatusOrder = t.TypeOf; -export const RuleExecutionStatusOrder = PositiveInteger; - export const ruleExecutionStatusToNumber = ( status: RuleExecutionStatus ): RuleExecutionStatusOrder => { diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.gen.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.gen.ts new file mode 100644 index 00000000000000..315dc77db6ba85 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.gen.ts @@ -0,0 +1,33 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { z } from 'zod'; + +/* + * NOTICE: Do not edit this file manually. + * This file is automatically generated by the OpenAPI Generator, @kbn/openapi-generator. + */ + +import { RuleExecutionStatus, RuleExecutionStatusOrder } from './execution_status.gen'; +import { RuleExecutionMetrics } from './execution_metrics.gen'; + +export type RuleExecutionSummary = z.infer; +export const RuleExecutionSummary = z.object({ + last_execution: z.object({ + /** + * Date of the last execution + */ + date: z.string().datetime(), + /** + * Status of the last execution + */ + status: RuleExecutionStatus, + status_order: RuleExecutionStatusOrder, + message: z.string(), + metrics: RuleExecutionMetrics, + }), +}); diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.schema.yaml b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.schema.yaml new file mode 100644 index 00000000000000..f00529670d58b0 --- /dev/null +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.schema.yaml @@ -0,0 +1,35 @@ +openapi: 3.0.0 +info: + title: Execution Summary Schema + version: not applicable +paths: {} +components: + x-codegen-enabled: true + schemas: + RuleExecutionSummary: + type: object + properties: + last_execution: + type: object + properties: + date: + description: Date of the last execution + type: string + format: date-time + status: + description: Status of the last execution + $ref: './execution_status.schema.yaml#/components/schemas/RuleExecutionStatus' + status_order: + $ref: './execution_status.schema.yaml#/components/schemas/RuleExecutionStatusOrder' + message: + type: string + metrics: + $ref: './execution_metrics.schema.yaml#/components/schemas/RuleExecutionMetrics' + required: + - date + - status + - status_order + - message + - metrics + required: + - last_execution diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.ts index bbe9e9ad5d7e7f..a747d2f021b7c5 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/model/execution_summary.ts @@ -5,17 +5,17 @@ * 2.0. */ -import * as t from 'io-ts'; import { IsoDateString } from '@kbn/securitysolution-io-ts-types'; -import { TRuleExecutionStatus, RuleExecutionStatusOrder } from './execution_status'; +import * as t from 'io-ts'; import { RuleExecutionMetrics } from './execution_metrics'; +import { TRuleExecutionStatus } from './execution_status'; export type RuleExecutionSummary = t.TypeOf; export const RuleExecutionSummary = t.type({ last_execution: t.type({ date: IsoDateString, status: TRuleExecutionStatus, - status_order: RuleExecutionStatusOrder, + status_order: t.number, message: t.string, metrics: RuleExecutionMetrics, }), diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.test.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.test.ts index 9dc071b7ca1eac..742290de8bf43e 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.test.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_monitoring/rule_execution_logs/get_rule_execution_results/get_rule_execution_results_route.test.ts @@ -5,8 +5,7 @@ * 2.0. */ -import { stringifyZodError } from '@kbn/securitysolution-es-utils'; -import { expectParseError, expectParseSuccess } from '../../../../../test/zod_helpers'; +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { RuleExecutionStatus } from '../../model'; import { GetRuleExecutionResultsRequestQuery } from './get_rule_execution_results_route.gen'; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/rule_preview/preview_rules_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/rule_preview/preview_rules_route.ts index b6d64dbc4d44a0..6f0c61834b1381 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/rule_preview/preview_rules_route.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/rule_preview/preview_rules_route.ts @@ -5,15 +5,13 @@ * 2.0. */ -import * as t from 'io-ts'; -import { SharedCreateProps, TypeSpecificCreateProps } from '../model'; +import * as z from 'zod'; +import { SharedCreateProps, TypeSpecificCreateProps } from '../model/rule_schema'; -export type PreviewRulesSchema = t.TypeOf; -export const previewRulesSchema = t.intersection([ - SharedCreateProps, - TypeSpecificCreateProps, - t.type({ invocationCount: t.number, timeframeEnd: t.string }), -]); +export type PreviewRulesSchema = z.infer; +export const PreviewRulesSchema = SharedCreateProps.and(TypeSpecificCreateProps).and( + z.object({ invocationCount: z.number(), timeframeEnd: z.string() }) +); export interface RulePreviewLogs { errors: string[]; diff --git a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts index cb67964ea7745f..dd1ecc4208ef79 100644 --- a/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts +++ b/x-pack/plugins/security_solution/common/api/detection_engine/signals_migration/create_signals_migration/create_signals_migration_route.ts @@ -8,7 +8,9 @@ import * as t from 'io-ts'; import { PositiveInteger, PositiveIntegerGreaterThanZero } from '@kbn/securitysolution-io-ts-types'; -import { IndexPatternArray } from '../../model'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { IndexPatternArray } from '../../model/rule_schema_legacy'; export const signalsReindexOptions = t.partial({ requests_per_second: t.number, diff --git a/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.gen.ts b/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.gen.ts index 2dffbc473ecc6f..986260c2e463fe 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.gen.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/model/schema/common.gen.ts @@ -65,8 +65,8 @@ export const Command = z.enum([ 'execute', 'upload', ]); -export const CommandEnum = Command.enum; export type CommandEnum = typeof Command.enum; +export const CommandEnum = Command.enum; export type Commands = z.infer; export const Commands = z.array(Command); @@ -79,8 +79,8 @@ export const Timeout = z.number().int().min(1); export type Status = z.infer; export const Status = z.enum(['failed', 'pending', 'successful']); -export const StatusEnum = Status.enum; export type StatusEnum = typeof Status.enum; +export const StatusEnum = Status.enum; export type Statuses = z.infer; export const Statuses = z.array(Status); @@ -99,8 +99,8 @@ export const WithOutputs = z.union([z.array(z.string().min(1)).min(1), z.string( export type Type = z.infer; export const Type = z.enum(['automated', 'manual']); -export const TypeEnum = Type.enum; export type TypeEnum = typeof Type.enum; +export const TypeEnum = Type.enum; export type Types = z.infer; export const Types = z.array(Type); diff --git a/x-pack/plugins/security_solution/common/api/endpoint/suggestions/get_suggestions.gen.ts b/x-pack/plugins/security_solution/common/api/endpoint/suggestions/get_suggestions.gen.ts index c1bc91e6ded867..5c4553d7d57af1 100644 --- a/x-pack/plugins/security_solution/common/api/endpoint/suggestions/get_suggestions.gen.ts +++ b/x-pack/plugins/security_solution/common/api/endpoint/suggestions/get_suggestions.gen.ts @@ -19,7 +19,7 @@ export type GetEndpointSuggestionsRequestParams = z.infer< >; export const GetEndpointSuggestionsRequestParams = z.object({ query: z.object({ - suggestion_type: z.enum(['eventFilters']).optional(), + suggestion_type: z.literal('eventFilters').optional(), }), }); export type GetEndpointSuggestionsRequestParamsInput = z.input< diff --git a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts index c164068f237095..864b4613857e22 100644 --- a/x-pack/plugins/security_solution/common/api/timeline/model/api.ts +++ b/x-pack/plugins/security_solution/common/api/timeline/model/api.ts @@ -14,11 +14,13 @@ import type { Maybe } from '../../../search_strategy'; import { Direction } from '../../../search_strategy'; import type { PinnedEvent } from '../pinned_events/pinned_events_route'; import { PinnedEventRuntimeType } from '../pinned_events/pinned_events_route'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports import { SavedObjectResolveAliasPurpose, SavedObjectResolveAliasTargetId, SavedObjectResolveOutcome, -} from '../../detection_engine/model/rule_schema'; +} from '../../detection_engine/model/rule_schema_legacy'; import { ErrorSchema, success, success_count as successCount } from '../../detection_engine'; export const BareNoteSchema = runtimeTypes.intersection([ diff --git a/x-pack/plugins/security_solution/common/constants.ts b/x-pack/plugins/security_solution/common/constants.ts index f6f406692e50db..c6edaf898f67ff 100644 --- a/x-pack/plugins/security_solution/common/constants.ts +++ b/x-pack/plugins/security_solution/common/constants.ts @@ -8,7 +8,6 @@ import { RuleNotifyWhen } from '@kbn/alerting-plugin/common'; import type { AddOptionsListControlProps } from '@kbn/controls-plugin/public'; import * as i18n from './translations'; - export { SecurityPageName } from '@kbn/security-solution-navigation'; /** diff --git a/x-pack/plugins/security_solution/common/detection_engine/constants.ts b/x-pack/plugins/security_solution/common/detection_engine/constants.ts index ff6e23e68aa63a..a2a07209997bfd 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/constants.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/constants.ts @@ -32,3 +32,7 @@ export const PREBUILT_RULES_PACKAGE_NAME = 'security_detection_engine'; * Rule signature id (`rule.rule_id`) of the prebuilt "Endpoint Security" rule. */ export const ELASTIC_SECURITY_RULE_ID = '9a1a2dae-0b5f-4c3d-8305-a268d404c306'; + +export const DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY = 'suppress' as const; + +export const MINIMUM_LICENSE_FOR_SUPPRESSION = 'platinum' as const; diff --git a/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts b/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts index 49d06ce33a78be..5750f35d893e20 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/transform_actions.ts @@ -5,7 +5,7 @@ * 2.0. */ -import type { RuleAction } from '@kbn/alerting-plugin/common'; +import type { RuleAction as AlertingRuleAction } from '@kbn/alerting-plugin/common'; import type { NormalizedAlertAction } from '@kbn/alerting-plugin/server/rules_client'; import type { NormalizedRuleAction } from '../api/detection_engine/rule_management/bulk_actions/bulk_actions_route'; import type { @@ -13,7 +13,7 @@ import type { RuleResponseAction, } from '../api/detection_engine/model/rule_response_actions'; import { RESPONSE_ACTION_TYPES } from '../api/detection_engine/model/rule_response_actions'; -import type { RuleAlertAction } from './types'; +import type { RuleAction } from '../api/detection_engine/model'; export const transformRuleToAlertAction = ({ group, @@ -23,12 +23,14 @@ export const transformRuleToAlertAction = ({ uuid, frequency, alerts_filter: alertsFilter, -}: RuleAlertAction): RuleAction => ({ +}: RuleAction): AlertingRuleAction => ({ group, id, - params, + params: params as AlertingRuleAction['params'], actionTypeId, - ...(alertsFilter && { alertsFilter }), + ...(alertsFilter && { + alertsFilter: alertsFilter as AlertingRuleAction['alertsFilter'], + }), ...(uuid && { uuid }), ...(frequency && { frequency }), }); @@ -41,7 +43,7 @@ export const transformAlertToRuleAction = ({ uuid, frequency, alertsFilter, -}: RuleAction): RuleAlertAction => ({ +}: AlertingRuleAction): RuleAction => ({ group, id, params, @@ -60,7 +62,7 @@ export const transformNormalizedRuleToAlertAction = ({ }: NormalizedRuleAction): NormalizedAlertAction => ({ group, id, - params, + params: params as AlertingRuleAction['params'], ...(alertsFilter && { alertsFilter }), ...(frequency && { frequency }), }); @@ -71,7 +73,7 @@ export const transformAlertToNormalizedRuleAction = ({ params, frequency, alertsFilter, -}: RuleAction): NormalizedRuleAction => ({ +}: AlertingRuleAction): NormalizedRuleAction => ({ group, id, params, diff --git a/x-pack/plugins/security_solution/common/detection_engine/types.ts b/x-pack/plugins/security_solution/common/detection_engine/types.ts index 1b3976e91b3c50..0d87a7e0f87554 100644 --- a/x-pack/plugins/security_solution/common/detection_engine/types.ts +++ b/x-pack/plugins/security_solution/common/detection_engine/types.ts @@ -5,13 +5,6 @@ * 2.0. */ -import type { RuleAction } from '@kbn/alerting-plugin/common'; - -export type RuleAlertAction = Omit & { - action_type_id: string; - alerts_filter?: RuleAction['alertsFilter']; -}; - /** * Defines the search types you can have from Elasticsearch within a * doc._source. It uses recursive types of "| SearchTypes[]" to designate diff --git a/x-pack/plugins/security_solution/common/endpoint/utils/package_v2.ts b/x-pack/plugins/security_solution/common/endpoint/utils/package_v2.ts new file mode 100644 index 00000000000000..926949bf9cd7fd --- /dev/null +++ b/x-pack/plugins/security_solution/common/endpoint/utils/package_v2.ts @@ -0,0 +1,13 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import semverLte from 'semver/functions/lte'; + +const MIN_ENDPOINT_PACKAGE_V2_VERSION = '8.12.0'; +export function isEndpointPackageV2(version: string) { + return semverLte(MIN_ENDPOINT_PACKAGE_V2_VERSION, version); +} diff --git a/x-pack/plugins/security_solution/common/endpoint/utils/transforms.ts b/x-pack/plugins/security_solution/common/endpoint/utils/transforms.ts index 2f40fc0367bc61..7d402108b9724e 100644 --- a/x-pack/plugins/security_solution/common/endpoint/utils/transforms.ts +++ b/x-pack/plugins/security_solution/common/endpoint/utils/transforms.ts @@ -5,11 +5,10 @@ * 2.0. */ -import semverLte from 'semver/functions/lte'; - import type { Client } from '@elastic/elasticsearch'; import type { TransformGetTransformStatsTransformStats } from '@elastic/elasticsearch/lib/api/typesWithBodyKey'; +import { isEndpointPackageV2 } from './package_v2'; import { usageTracker } from '../data_loaders/usage_tracker'; import { metadataCurrentIndexPattern, @@ -172,8 +171,3 @@ async function waitFor( } } } - -const MIN_ENDPOINT_PACKAGE_V2_VERSION = '8.12.0'; -export function isEndpointPackageV2(version: string) { - return semverLte(MIN_ENDPOINT_PACKAGE_V2_VERSION, version); -} diff --git a/x-pack/plugins/security_solution/common/risk_engine/risk_score_calculation/request_schema.ts b/x-pack/plugins/security_solution/common/risk_engine/risk_score_calculation/request_schema.ts index 880931ebc0a18a..6058f60e1e1c6d 100644 --- a/x-pack/plugins/security_solution/common/risk_engine/risk_score_calculation/request_schema.ts +++ b/x-pack/plugins/security_solution/common/risk_engine/risk_score_calculation/request_schema.ts @@ -6,7 +6,9 @@ */ import * as t from 'io-ts'; -import { DataViewId } from '../../api/detection_engine'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { DataViewId } from '../../api/detection_engine/model/rule_schema_legacy'; import { afterKeysSchema } from '../after_keys'; import { identifierTypeSchema } from '../identifier_types'; import { riskWeightsSchema } from '../risk_weights/schema'; diff --git a/x-pack/plugins/security_solution/common/risk_engine/risk_score_preview/request_schema.ts b/x-pack/plugins/security_solution/common/risk_engine/risk_score_preview/request_schema.ts index beeffc98bbe0d6..c4402483116365 100644 --- a/x-pack/plugins/security_solution/common/risk_engine/risk_score_preview/request_schema.ts +++ b/x-pack/plugins/security_solution/common/risk_engine/risk_score_preview/request_schema.ts @@ -6,7 +6,9 @@ */ import * as t from 'io-ts'; -import { DataViewId } from '../../api/detection_engine/model/rule_schema'; +// TODO https://github.com/elastic/security-team/issues/7491 +// eslint-disable-next-line no-restricted-imports +import { DataViewId } from '../../api/detection_engine/model/rule_schema_legacy'; import { afterKeysSchema } from '../after_keys'; import { identifierTypeSchema } from '../identifier_types'; import { rangeSchema } from '../range'; diff --git a/x-pack/plugins/security_solution/public/assistant/content/prompt_contexts/index.tsx b/x-pack/plugins/security_solution/public/assistant/content/prompt_contexts/index.tsx index 000eb3bdd8065e..e7d88978e769b7 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/prompt_contexts/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/content/prompt_contexts/index.tsx @@ -16,6 +16,7 @@ export const PROMPT_CONTEXT_ALERT_CATEGORY = 'alert'; export const PROMPT_CONTEXT_EVENT_CATEGORY = 'event'; export const PROMPT_CONTEXT_DETECTION_RULES_CATEGORY = 'detection-rules'; export const DATA_QUALITY_DASHBOARD_CATEGORY = 'data-quality-dashboard'; +export const KNOWLEDGE_BASE_CATEGORY = 'knowledge-base'; /** * Global list of PromptContexts intended to be used throughout Security Solution. diff --git a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx index c35598f8898baa..799087f202e984 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx +++ b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/index.tsx @@ -8,6 +8,7 @@ import type { QuickPrompt } from '@kbn/elastic-assistant'; import * as i18n from './translations'; import { + KNOWLEDGE_BASE_CATEGORY, PROMPT_CONTEXT_ALERT_CATEGORY, PROMPT_CONTEXT_DETECTION_RULES_CATEGORY, PROMPT_CONTEXT_EVENT_CATEGORY, @@ -26,6 +27,13 @@ export const BASE_SECURITY_QUICK_PROMPTS: QuickPrompt[] = [ categories: [PROMPT_CONTEXT_ALERT_CATEGORY], isDefault: true, }, + { + title: i18n.ESQL_QUERY_GENERATION_TITLE, + prompt: i18n.ESQL_QUERY_GENERATION_PROMPT, + color: '#9170B8', + categories: [KNOWLEDGE_BASE_CATEGORY], + isDefault: true, + }, { title: i18n.RULE_CREATION_TITLE, prompt: i18n.RULE_CREATION_PROMPT, diff --git a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts index 1d122b0169be2e..41b9e7ddb197bc 100644 --- a/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts +++ b/x-pack/plugins/security_solution/public/assistant/content/quick_prompts/translations.ts @@ -22,6 +22,21 @@ export const ALERT_SUMMARIZATION_PROMPT = i18n.translate( } ); +export const ESQL_QUERY_GENERATION_TITLE = i18n.translate( + 'xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationTitle', + { + defaultMessage: 'ES|QL Query Generation', + } +); + +export const ESQL_QUERY_GENERATION_PROMPT = i18n.translate( + 'xpack.securitySolution.assistant.quickPrompts.esqlQueryGenerationPrompt', + { + defaultMessage: + "As an expert user of Elastic Security, please generate an accurate and valid ESQL query to detect the use case below. Your response should be formatted to be able to use immediately in an Elastic Security timeline or detection rule. Take your time with the answer, check your knowledge really well on all the functions I am asking for. For ES|QL answers specifically, you should only ever answer with what's available in your private knowledge. I cannot afford for queries to be inaccurate. Assume I am using the Elastic Common Schema and Elastic Agent.\n\nEnsure the answers are formatted in a way which is easily copyable as a separate code block in markdown.", + } +); + export const RULE_CREATION_TITLE = i18n.translate( 'xpack.securitySolution.assistant.quickPrompts.ruleCreationTitle', { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts index 2b4dbacadac8e8..1c73a81b4d26ef 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_creation/helpers.ts @@ -46,8 +46,8 @@ import { GroupByOptions, } from '../../../../detections/pages/detection_engine/rules/types'; import type { RuleCreateProps } from '../../../../../common/api/detection_engine/model/rule_schema'; -import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../common/api/detection_engine/model/rule_schema'; import { stepActionsDefaultValue } from '../../../../detections/components/rules/step_rule_actions'; +import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../common/detection_engine/constants'; export const getTimeTypeValue = (time: string): { unit: Unit; value: number } => { const timeObj: { unit: Unit; value: number } = { @@ -609,7 +609,7 @@ export const formatActionsStepData = (actionsStepData: ActionsStepRule): Actions const { actions = [], responseActions, enabled, kibanaSiemAppUrl } = actionsStepData; return { - actions: actions.map(transformAlertToRuleAction), + actions: actions.map((action) => transformAlertToRuleAction(action)), response_actions: responseActions?.map(transformAlertToRuleResponseAction), enabled, meta: { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx index 419385b9d3994f..60824648b18e05 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_creation_ui/pages/rule_editing/index.tsx @@ -26,8 +26,10 @@ import type { DataViewListItem } from '@kbn/data-views-plugin/common'; import { isEsqlRule } from '../../../../../common/detection_engine/utils'; import { RulePreview } from '../../../../detections/components/rules/rule_preview'; import { getIsRulePreviewDisabled } from '../../../../detections/components/rules/rule_preview/helpers'; -import type { RuleUpdateProps } from '../../../../../common/api/detection_engine/model/rule_schema'; -import type { Rule } from '../../../rule_management/logic'; +import type { + RuleResponse, + RuleUpdateProps, +} from '../../../../../common/api/detection_engine/model/rule_schema'; import { useRule, useUpdateRule } from '../../../rule_management/logic'; import { useListsConfig } from '../../../../detections/containers/detection_engine/lists/use_lists_config'; import { SecuritySolutionPageWrapper } from '../../../../common/components/page_wrapper'; @@ -69,7 +71,7 @@ import { useRuleForms, useRuleIndexPattern } from '../form'; import { useEsqlIndex, useEsqlQueryForAboutStep } from '../../hooks'; import { CustomHeaderPageMemo } from '..'; -const EditRulePageComponent: FC<{ rule: Rule }> = ({ rule }) => { +const EditRulePageComponent: FC<{ rule: RuleResponse }> = ({ rule }) => { const [, dispatchToaster] = useStateToaster(); const [ { @@ -176,7 +178,7 @@ const EditRulePageComponent: FC<{ rule: Rule }> = ({ rule }) => { const loading = userInfoLoading || listsConfigLoading; const { isSavedQueryLoading, savedQuery } = useGetSavedQuery({ - savedQueryId: rule?.saved_id, + savedQueryId: 'saved_id' in rule ? rule.saved_id : undefined, ruleType: rule?.type, }); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response.ts deleted file mode 100644 index fb1fdfc1fcc99f..00000000000000 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response.ts +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import type { Rule } from '../../../rule_management/logic'; -import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; - -/* - * This is a temporary workaround to suppress TS errors when using - * rule section components on the rule details page. - * - * The rule details page passes a Rule object to the rule section components, - * but section components expect a RuleResponse object. Rule and RuleResponse - * are basically same object type with only a few minor differences. - * This function casts the Rule object to RuleResponse. - * - * In the near future we'll start using codegen to generate proper response - * types and the rule details page will start passing RuleResponse objects, - * so this workaround will no longer be needed. - */ -export const castRuleAsRuleResponse = (rule: Rule) => rule as Partial; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx index 1dd01aeff817bb..876cfb09065632 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/index.tsx @@ -58,7 +58,6 @@ import { } from '../../../../common/components/link_to/redirect_to_detection_engine'; import { SiemSearchBar } from '../../../../common/components/search_bar'; import { SecuritySolutionPageWrapper } from '../../../../common/components/page_wrapper'; -import type { Rule } from '../../../rule_management/logic'; import { useListsConfig } from '../../../../detections/containers/detection_engine/lists/use_lists_config'; import { SpyRoute } from '../../../../common/utils/route/spy_routes'; import { StepAboutRuleToggleDetails } from '../../../../detections/components/rules/step_about_rule_details'; @@ -74,6 +73,7 @@ import { import { RuleSwitch } from '../../../../detections/components/rules/rule_switch'; import { StepPanel } from '../../../../detections/components/rules/step_panel'; import { + getMachineLearningJobId, getStepsData, redirectToDetections, } from '../../../../detections/pages/detection_engine/rules/helpers'; @@ -124,7 +124,7 @@ import { MissingPrivilegesCallOut } from '../../../../detections/components/call import { useRuleWithFallback } from '../../../rule_management/logic/use_rule_with_fallback'; import type { BadgeOptions } from '../../../../common/components/header_page/types'; import type { AlertsStackByField } from '../../../../detections/components/alerts_kpis/common/types'; -import type { Status } from '../../../../../common/api/detection_engine'; +import type { RuleResponse, Status } from '../../../../../common/api/detection_engine'; import { AlertsTableFilterGroup } from '../../../../detections/components/alerts_table/alerts_filter_group'; import { useSignalHelpers } from '../../../../common/containers/sourcerer/use_signal_helpers'; import { HeaderPage } from '../../../../common/components/header_page'; @@ -141,7 +141,6 @@ import { RuleScheduleSection } from '../../../rule_management/components/rule_de // eslint-disable-next-line no-restricted-imports import { useLegacyUrlRedirect } from './use_redirect_legacy_url'; import { RuleDetailTabs, useRuleDetailsTabs } from './use_rule_details_tabs'; -import { castRuleAsRuleResponse } from './cast_rule_as_rule_response'; const RULE_EXCEPTION_LIST_TYPES = [ ExceptionListTypeEnum.DETECTION, @@ -238,12 +237,14 @@ const RuleDetailsPageComponent: React.FC = ({ } = useRuleWithFallback(ruleId); const { pollForSignalIndex } = useSignalHelpers(); - const [rule, setRule] = useState(null); + const [rule, setRule] = useState(null); const isLoading = ruleLoading && rule == null; const { starting: isStartingJobs, startMlJobs } = useStartMlJobs(); const startMlJobsIfNeeded = useCallback(async () => { - await startMlJobs(rule?.machine_learning_job_id); + if (rule) { + await startMlJobs(getMachineLearningJobId(rule)); + } }, [rule, startMlJobs]); const pageTabs = useRuleDetailsTabs({ rule, ruleId, isExistingRule, hasIndexRead }); @@ -649,7 +650,7 @@ const RuleDetailsPageComponent: React.FC = ({ {rule !== null && !isStartingJobs && ( @@ -659,9 +660,7 @@ const RuleDetailsPageComponent: React.FC = ({ - {rule != null && ( - - )} + {rule != null && } {hasActions && ( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/legacy_url_conflict_callout.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/legacy_url_conflict_callout.test.tsx index 6bce996bc14fca..0582cc13eb92b2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/legacy_url_conflict_callout.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/legacy_url_conflict_callout.test.tsx @@ -92,6 +92,7 @@ const mockRule: Rule = { severity: 'low', type: 'query', query: 'some query', + language: 'kuery', index: ['index-1'], interval: '5m', references: [], @@ -101,8 +102,8 @@ const mockRule: Rule = { max_signals: 100, tags: [], threat: [], - throttle: null, version: 1, + revision: 1, exceptions_list: [], created_at: '2020-04-09T09:43:51.778Z', created_by: 'elastic', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts index ee0da0edbfdb97..d7971cce43f805 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_redirect_legacy_url.test.ts @@ -103,8 +103,9 @@ const mockRule: Rule = { max_signals: 100, tags: [], threat: [], - throttle: null, version: 1, + revision: 1, + language: 'kuery', exceptions_list: [], created_at: '2020-04-09T09:43:51.778Z', created_by: 'elastic', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx index 1dc2d4ee29442c..cf4446c7fea422 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_details_ui/pages/rule_details/use_rule_details_tabs.test.tsx @@ -32,6 +32,7 @@ const mockRule: Rule = { severity: 'low', type: 'query', query: 'some query', + language: 'kuery', index: ['index-1'], interval: '5m', references: [], @@ -41,8 +42,8 @@ const mockRule: Rule = { max_signals: 100, tags: [], threat: [], - throttle: null, version: 1, + revision: 1, exceptions_list: [], created_at: '2020-04-09T09:43:51.778Z', created_by: 'elastic', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx index 9a50076530983c..d4108c3eddede9 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/add_exception_flyout/index.tsx @@ -492,10 +492,19 @@ export const AddExceptionFlyout = memo(function AddExceptionFlyout({ {errorSubmitting != null && ( <> - + {i18n.SUBMIT_ERROR_DISMISS_MESSAGE} - + {i18n.SUBMIT_ERROR_DISMISS_BUTTON} diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/error_callout/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/error_callout/index.tsx index 112c15969d7fde..c154544f3937cc 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/error_callout/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/error_callout/index.tsx @@ -18,9 +18,9 @@ import { import type { List } from '@kbn/securitysolution-io-ts-list-types'; import type { HttpSetup } from '@kbn/core/public'; -import type { Rule } from '../../../rule_management/logic/types'; import * as i18n from '../../utils/translations'; import { useDisassociateExceptionList } from '../../../rule_management/logic/use_disassociate_exception_list'; +import type { RuleResponse } from '../../../../../common/api/detection_engine'; export interface ErrorInfo { reason: string | null; @@ -31,7 +31,7 @@ export interface ErrorInfo { export interface ErrorCalloutProps { http: HttpSetup; - rule: Rule | null; + rule: RuleResponse | null; errorInfo: ErrorInfo; onCancel: () => void; onSuccess: (listId: string) => void; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/index.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/index.test.tsx index 914dbc40be1787..2cece43d06f9a8 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/index.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/index.test.tsx @@ -12,7 +12,6 @@ import { ExceptionsAddToRulesTable } from '.'; import { TestProviders } from '../../../../../common/mock'; import { useFindRules } from '../../../../rule_management/logic/use_find_rules'; import { getRulesSchemaMock } from '../../../../../../common/api/detection_engine/model/rule_schema/mocks'; -import type { Rule } from '../../../../rule_management/logic/types'; jest.mock('../../../../rule_management/logic/use_find_rules'); @@ -40,7 +39,7 @@ describe('ExceptionsAddToRulesTable', () => { const wrapper = render( @@ -64,7 +63,7 @@ describe('ExceptionsAddToRulesTable', () => { const { queryByTestId, getByText } = render( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/index.tsx index dbd11e0c486f36..2a2e7559ee9c96 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/index.tsx @@ -9,12 +9,12 @@ import React from 'react'; import type { Search } from '@elastic/eui'; import { EuiSkeletonText, EuiSpacer, EuiPanel, EuiText, EuiInMemoryTable } from '@elastic/eui'; -import type { Rule } from '../../../../rule_management/logic/types'; import { useAddToRulesTable } from './use_add_to_rules_table'; +import type { RuleResponse } from '../../../../../../common/api/detection_engine'; interface ExceptionsAddToRulesComponentProps { - initiallySelectedRules?: Rule[]; - onRuleSelectionChange: (rulesSelectedToAdd: Rule[]) => void; + initiallySelectedRules?: RuleResponse[]; + onRuleSelectionChange: (rulesSelectedToAdd: RuleResponse[]) => void; } const ExceptionsAddToRulesTableComponent: React.FC = ({ @@ -39,7 +39,7 @@ const ExceptionsAddToRulesTableComponent: React.FC {addToSelectedRulesDescription} - + tableLayout="auto" search={searchOptions as Search} data-test-subj="addExceptionToRulesTable" diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/link_rule_switch/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/link_rule_switch/index.tsx index b01fe7209dd1a7..080a59a8082f90 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/link_rule_switch/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/link_rule_switch/index.tsx @@ -6,7 +6,7 @@ */ import React, { memo, useCallback, useMemo } from 'react'; import { EuiFlexItem, EuiSwitch } from '@elastic/eui'; -import type { Rule } from '../../../../../rule_management/logic/types'; +import type { RuleResponse } from '../../../../../../../common/api/detection_engine'; export const LinkRuleSwitch = memo( ({ @@ -14,9 +14,9 @@ export const LinkRuleSwitch = memo( linkedRules, onRuleLinkChange, }: { - rule: Rule; - linkedRules: Rule[]; - onRuleLinkChange: (rulesSelectedToAdd: Rule[]) => void; + rule: RuleResponse; + linkedRules: RuleResponse[]; + onRuleLinkChange: (rulesSelectedToAdd: RuleResponse[]) => void; }) => { const isRuleLinked = useMemo( () => Boolean(linkedRules.find((r) => r.id === rule.id)), diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/use_add_to_rules_table.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/use_add_to_rules_table.tsx index 74b7905a37b17f..d5065d6a18308e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/use_add_to_rules_table.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/add_to_rules_table/use_add_to_rules_table.tsx @@ -15,14 +15,14 @@ import { i18n } from '@kbn/i18n'; import * as myI18n from './translations'; import * as commonI18n from '../translations'; -import type { Rule } from '../../../../rule_management/logic/types'; import { getRulesTableColumn } from '../utils'; import { LinkRuleSwitch } from './link_rule_switch'; import { useFindRules } from '../../../../rule_management/logic/use_find_rules'; +import type { RuleResponse } from '../../../../../../common/api/detection_engine/model'; export interface ExceptionsAddToRulesComponentProps { - initiallySelectedRules?: Rule[]; - onRuleSelectionChange: (rulesSelectedToAdd: Rule[]) => void; + initiallySelectedRules?: RuleResponse[]; + onRuleSelectionChange: (rulesSelectedToAdd: RuleResponse[]) => void; } export const useAddToRulesTable = ({ initiallySelectedRules, @@ -48,7 +48,7 @@ export const useAddToRulesTable = ({ showPerPageOptions: false, }); - const [linkedRules, setLinkedRules] = useState(initiallySelectedRules || []); + const [linkedRules, setLinkedRules] = useState(initiallySelectedRules || []); useEffect(() => { onRuleSelectionChange(linkedRules); }, [linkedRules, onRuleSelectionChange]); @@ -64,12 +64,15 @@ export const useAddToRulesTable = ({ ); const tagOptions = useMemo(() => { - const uniqueTags = sortedRulesByLinkedRulesOnTop.reduce((acc: Set, item: Rule) => { - const { tags } = item; + const uniqueTags = sortedRulesByLinkedRulesOnTop.reduce( + (acc: Set, item: RuleResponse) => { + const { tags } = item; - tags.forEach((tag) => acc.add(tag)); - return acc; - }, new Set()); + tags.forEach((tag) => acc.add(tag)); + return acc; + }, + new Set() + ); return Array.from(uniqueTags).map((tag) => ({ value: tag, name: tag, field: 'tags' })); }, [sortedRulesByLinkedRulesOnTop]); @@ -97,14 +100,14 @@ export const useAddToRulesTable = ({ [tagOptions] ); - const rulesTableColumnsWithLinkSwitch: Array> = useMemo( + const rulesTableColumnsWithLinkSwitch: Array> = useMemo( () => [ { field: 'link', name: commonI18n.LINK_COLUMN, align: 'left' as HorizontalAlignment, 'data-test-subj': 'ruleActionLinkRuleSwitch', - render: (_: unknown, rule: Rule) => ( + render: (_: unknown, rule: RuleResponse) => ( ), }, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/item_conditions/index.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/item_conditions/index.tsx index 30def4a88c4395..4467b18f0b10e1 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/item_conditions/index.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/item_conditions/index.tsx @@ -27,7 +27,7 @@ import type { import type { DataViewBase } from '@kbn/es-query'; import styled, { css } from 'styled-components'; import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; -import { hasEqlSequenceQuery, isEqlRule } from '../../../../../../common/detection_engine/utils'; +import { hasEqlSequenceQuery } from '../../../../../../common/detection_engine/utils'; import type { Rule } from '../../../../rule_management/logic/types'; import { useKibana } from '../../../../../common/lib/kibana'; import * as i18n from './translations'; @@ -111,7 +111,7 @@ const ExceptionsConditionsComponent: React.FC { return ( - rules != null && rules.some((rule) => isEqlRule(rule.type) && hasEqlSequenceQuery(rule.query)) + rules != null && rules.some((rule) => rule.type === 'eql' && hasEqlSequenceQuery(rule.query)) ); }, [rules]); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/utils.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/utils.tsx index 0a92a46592dfda..fa9d84f9216bf2 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/utils.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/components/flyout_components/utils.tsx @@ -33,9 +33,9 @@ import type { ExceptionListRuleReferencesInfoSchema, ExceptionListRuleReferencesSchema, } from '../../../../../common/api/detection_engine/rule_exceptions'; -import type { Rule } from '../../../rule_management/logic/types'; import { LinkToRuleDetails, LinkToListDetails } from '../../../../exceptions/components'; import * as i18n from './translations'; +import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema'; /** * Adds user defined name to all new exceptionItems @@ -261,7 +261,7 @@ export const getRulesTableColumn = () => [ align: 'left' as HorizontalAlignment, name: i18n.TAGS_COLUMN, 'data-test-subj': 'ruleNameCell', - render: (tags: Rule['tags']) => { + render: (tags: RuleResponse['tags']) => { if (tags.length === 0) { return null; } @@ -286,7 +286,7 @@ export const getRulesTableColumn = () => [ { name: i18n.ACTION_COLUMN, 'data-test-subj': 'ruleAction-view', - render: (rule: Rule) => { + render: (rule: RuleResponse) => { return ( { exceptions: CreateRuleExceptionListItemSchema[], rules: Rule[] ): Promise => { - setIsLoading(true); + try { + setIsLoading(true); - // TODO: Update once bulk route is added - const result = await Promise.all( - rules.map(async (rule) => - addRuleExceptions({ - items: exceptions, - ruleId: rule.id, - signal: abortCtrl.signal, - }) - ) - ); + // TODO: Update once bulk route is added + const result = await Promise.all( + rules.map(async (rule) => + addRuleExceptions({ + items: exceptions, + ruleId: rule.id, + signal: abortCtrl.signal, + }) + ) + ); - setIsLoading(false); + setIsLoading(false); - return result.flatMap((r) => r); + return result.flatMap((r) => r); + } catch (e) { + setIsLoading(false); + throw e; + } }; addRuleExceptionFunc.current = addExceptionItemsToRule; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_create_update_exception.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_create_update_exception.tsx index fbe9c0d46e6b3d..2a302a8b0577c5 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_create_update_exception.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_create_update_exception.tsx @@ -36,25 +36,30 @@ export const useCreateOrUpdateException = (): ReturnUseCreateOrUpdateException = const abortCtrl = new AbortController(); const onCreateOrUpdateExceptionItem: CreateOrUpdateExceptionItemsFunc = async (items) => { - setIsLoading(true); - const itemsAdded = await Promise.all( - items.map((item: ExceptionListItemSchema | CreateExceptionListItemSchema) => { - if ('id' in item && item.id != null) { - const formattedExceptionItem = formatExceptionItemForUpdate(item); - return updateExceptionListItem({ - listItem: formattedExceptionItem, - }); - } else { - return addExceptionListItem({ - listItem: item, - }); - } - }) - ); + try { + setIsLoading(true); + const itemsAdded = await Promise.all( + items.map((item: ExceptionListItemSchema | CreateExceptionListItemSchema) => { + if ('id' in item && item.id != null) { + const formattedExceptionItem = formatExceptionItemForUpdate(item); + return updateExceptionListItem({ + listItem: formattedExceptionItem, + }); + } else { + return addExceptionListItem({ + listItem: item, + }); + } + }) + ); - setIsLoading(false); + setIsLoading(false); - return itemsAdded; + return itemsAdded; + } catch (e) { + setIsLoading(false); + throw e; + } }; addOrUpdateExceptionRef.current = onCreateOrUpdateExceptionItem; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx index c27a195f1324d0..a064c19cc8654e 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_exception_flyout_data.tsx @@ -18,6 +18,7 @@ import { useFetchIndex } from '../../../common/containers/source'; import * as i18n from '../../../common/containers/source/translations'; import { useRuleIndices } from '../../rule_management/logic/use_rule_indices'; +import { getMachineLearningJobId } from '../../../detections/pages/detection_engine/rules/helpers'; export interface ReturnUseFetchExceptionFlyoutData { isLoading: boolean; @@ -40,10 +41,6 @@ export const useFetchIndexPatterns = (rules: Rule[] | null): ReturnUseFetchExcep () => rules != null && isSingleRule && rules[0].type === 'machine_learning', [isSingleRule, rules] ); - const isEsqlRule = useMemo( - () => rules != null && isSingleRule && rules[0].type === 'esql', - [isSingleRule, rules] - ); useEffect(() => { const fetchAndSetActiveSpace = async () => { @@ -56,28 +53,33 @@ export const useFetchIndexPatterns = (rules: Rule[] | null): ReturnUseFetchExcep }, [spaces]); // If data view is defined, it superceeds use of rule defined index patterns. // If no rule is available, use fields from default data view id. - const memoDataViewId = useMemo( - () => - rules != null && isSingleRule - ? rules[0].data_view_id || null - : `security-solution-${activeSpaceId}`, - [isSingleRule, rules, activeSpaceId] - ); + const memoDataViewId = useMemo(() => { + if (rules != null && isSingleRule) { + return ('data_view_id' in rules[0] && rules[0].data_view_id) || null; + } + return `security-solution-${activeSpaceId}`; + }, [isSingleRule, rules, activeSpaceId]); const memoNonDataViewIndexPatterns = useMemo(() => { - if (isEsqlRule) { + if (rules != null && isSingleRule && rules[0].type === 'esql') { return getIndexListFromEsqlQuery(rules?.[0].query); } - return !memoDataViewId && rules != null && isSingleRule && rules[0].index != null + return !memoDataViewId && + rules != null && + isSingleRule && + 'index' in rules[0] && + rules[0].index != null ? rules[0].index : []; - }, [memoDataViewId, isSingleRule, rules, isEsqlRule]); + }, [memoDataViewId, isSingleRule, rules]); // Index pattern logic for ML - const memoMlJobIds = useMemo( - () => (isMLRule && isSingleRule && rules != null ? rules[0].machine_learning_job_id ?? [] : []), - [isMLRule, isSingleRule, rules] - ); + const memoMlJobIds = useMemo(() => { + if (isMLRule && isSingleRule && rules != null) { + return getMachineLearningJobId(rules[0]) ?? []; + } + return []; + }, [isMLRule, isSingleRule, rules]); const { mlJobLoading, ruleIndices: mlRuleIndices } = useRuleIndices(memoMlJobIds); // We only want to provide a non empty array if it's an ML rule and we were able to fetch diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_fetch_or_create_rule_exception_list.test.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_fetch_or_create_rule_exception_list.test.tsx index b37c9d489029f1..6cca3e02e3223d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_fetch_or_create_rule_exception_list.test.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_fetch_or_create_rule_exception_list.test.tsx @@ -73,7 +73,7 @@ describe('useFetchOrCreateRuleExceptionList', () => { }; const ruleWithoutExceptionLists = { ...savedRuleMock, - exceptions_list: undefined, + exceptions_list: [], }; beforeEach(() => { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_fetch_or_create_rule_exception_list.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_fetch_or_create_rule_exception_list.tsx index a42ecbf5864404..54c5522d3bb7c6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_fetch_or_create_rule_exception_list.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_exceptions/logic/use_fetch_or_create_rule_exception_list.tsx @@ -20,14 +20,14 @@ import { import { ENDPOINT_LIST_ID } from '@kbn/securitysolution-list-constants'; import type { HttpStart } from '@kbn/core/public'; -import type { Rule } from '../../rule_management/logic/types'; import { fetchRuleById, patchRule } from '../../rule_management/api/api'; +import type { RuleResponse } from '../../../../common/api/detection_engine'; export type ReturnUseFetchOrCreateRuleExceptionList = [boolean, ExceptionListSchema | null]; export interface UseFetchOrCreateRuleExceptionListProps { http: HttpStart; - ruleId: Rule['id']; + ruleId: RuleResponse['id']; exceptionListType: ExceptionListSchema['type']; onError: (arg: Error, code: number | null, message: string | null) => void; onSuccess?: (ruleWasChanged: boolean) => void; @@ -56,7 +56,7 @@ export const useFetchOrCreateRuleExceptionList = ({ let isSubscribed = true; const abortCtrl = new AbortController(); - async function createExceptionList(ruleResponse: Rule): Promise { + async function createExceptionList(ruleResponse: RuleResponse): Promise { let newExceptionList: ExceptionListSchema; if (exceptionListType === 'endpoint') { const possibleEndpointExceptionList = await addEndpointExceptionList({ @@ -94,7 +94,7 @@ export const useFetchOrCreateRuleExceptionList = ({ } async function createAndAssociateExceptionList( - ruleResponse: Rule + ruleResponse: RuleResponse ): Promise { const newExceptionList = await createExceptionList(ruleResponse); @@ -120,14 +120,16 @@ export const useFetchOrCreateRuleExceptionList = ({ return Promise.resolve(newExceptionList); } - async function fetchRule(): Promise { + async function fetchRule(): Promise { return fetchRuleById({ id: ruleId, signal: abortCtrl.signal, }); } - async function fetchRuleExceptionLists(ruleResponse: Rule): Promise { + async function fetchRuleExceptionLists( + ruleResponse: RuleResponse + ): Promise { const exceptionListReferences = ruleResponse.exceptions_list; if (exceptionListReferences && exceptionListReferences.length > 0) { const exceptionListPromises = exceptionListReferences.map( diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/__mocks__/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/__mocks__/api.ts index 91304c44b4e490..cd4f8236eddfb7 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/__mocks__/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/__mocks__/api.ts @@ -15,7 +15,6 @@ import type { UpdateRulesProps, PrePackagedRulesStatusResponse, BasicFetchProps, - Rule, FetchRuleProps, FetchRulesResponse, FetchRulesProps, @@ -51,7 +50,7 @@ export const createPrepackagedRules = async ({ signal }: BasicFetchProps): Promi Promise.resolve(true); export const fetchRuleById = jest.fn( - async ({ id, signal }: FetchRuleProps): Promise => savedRuleMock + async ({ id, signal }: FetchRuleProps): Promise => savedRuleMock ); export const fetchRules = async (_: FetchRulesProps): Promise => diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts index 78a788c482654a..860e0fc86e8501 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/api.ts @@ -77,7 +77,6 @@ import type { PatchRuleProps, PrePackagedRulesStatusResponse, PreviewRulesProps, - Rule, RulesSnoozeSettingsBatchResponse, RulesSnoozeSettingsMap, UpdateRulesProps, @@ -105,15 +104,15 @@ export const createRule = async ({ rule, signal }: CreateRulesProps): Promise An updated rule + * @returns Promise An updated rule * * In fact this function should return Promise but it'd require massive refactoring. * It should be addressed as a part of OpenAPI schema adoption. * * @throws An error if response is not OK */ -export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise => - KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { +export const updateRule = async ({ rule, signal }: UpdateRulesProps): Promise => + KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { method: 'PUT', version: '2023-10-31', body: JSON.stringify(rule), @@ -208,15 +207,15 @@ export const fetchRules = async ({ * @param id Rule ID's (not rule_id) * @param signal to cancel request * - * @returns Promise + * @returns Promise * * In fact this function should return Promise but it'd require massive refactoring. * It should be addressed as a part of OpenAPI schema adoption. * * @throws An error if response is not OK */ -export const fetchRuleById = async ({ id, signal }: FetchRuleProps): Promise => - KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { +export const fetchRuleById = async ({ id, signal }: FetchRuleProps): Promise => + KibanaServices.get().http.fetch(DETECTION_ENGINE_RULES_URL, { method: 'GET', version: '2023-10-31', query: { id }, @@ -297,10 +296,10 @@ export interface BulkActionSummary { } export interface BulkActionResult { - updated: Rule[]; - created: Rule[]; - deleted: Rule[]; - skipped: Rule[]; + updated: RuleResponse[]; + created: RuleResponse[]; + deleted: RuleResponse[]; + skipped: RuleResponse[]; } export interface BulkActionAggregatedError { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts index 197b97effa1f8f..802d5228193e8d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_fetch_rule_by_id_query.ts @@ -8,9 +8,9 @@ import type { UseQueryOptions } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useCallback } from 'react'; +import type { RuleResponse } from '../../../../../common/api/detection_engine'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { transformInput } from '../../../../detections/containers/detection_engine/rules/transforms'; -import type { Rule } from '../../logic'; import { fetchRuleById } from '../api'; import { DEFAULT_QUERY_OPTIONS } from './constants'; @@ -24,8 +24,8 @@ const FIND_ONE_RULE_QUERY_KEY = ['GET', DETECTION_ENGINE_RULES_URL]; * @param options - react-query options * @returns useQuery result */ -export const useFetchRuleByIdQuery = (id: string, options?: UseQueryOptions) => { - return useQuery( +export const useFetchRuleByIdQuery = (id: string, options?: UseQueryOptions) => { + return useQuery( [...FIND_ONE_RULE_QUERY_KEY, id], async ({ signal }) => { const response = await fetchRuleById({ signal, id }); @@ -74,7 +74,7 @@ export const useUpdateRuleByIdCache = () => { * we can merge those rules with the existing cache to avoid an extra roundtrip to re-fetch updated rules. */ return useCallback( - (updatedRuleResponse: Rule) => { + (updatedRuleResponse: RuleResponse) => { queryClient.setQueryData['data']>( [...FIND_ONE_RULE_QUERY_KEY, updatedRuleResponse.id], transformInput(updatedRuleResponse) diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_find_rules_query.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_find_rules_query.ts index 38293c421bb704..1311fbb19dbefa 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_find_rules_query.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_find_rules_query.ts @@ -8,8 +8,9 @@ import type { UseQueryOptions } from '@tanstack/react-query'; import { useQuery, useQueryClient } from '@tanstack/react-query'; import { useCallback } from 'react'; +import type { RuleResponse } from '../../../../../common/api/detection_engine'; import { DETECTION_ENGINE_RULES_URL_FIND } from '../../../../../common/constants'; -import type { FilterOptions, PaginationOptions, Rule, SortingOptions } from '../../logic'; +import type { FilterOptions, PaginationOptions, SortingOptions } from '../../logic'; import { fetchRules } from '../api'; import { DEFAULT_QUERY_OPTIONS } from './constants'; @@ -22,7 +23,7 @@ export interface FindRulesQueryArgs { const FIND_RULES_QUERY_KEY = ['GET', DETECTION_ENGINE_RULES_URL_FIND]; export interface RulesQueryResponse { - rules: Rule[]; + rules: RuleResponse[]; total: number; } @@ -100,7 +101,7 @@ export const useUpdateRulesCache = () => { * we can merge those rules with the existing cache to avoid an extra roundtrip to re-fetch updated rules. */ return useCallback( - (newRules: Rule[]) => { + (newRules: RuleResponse[]) => { queryClient.setQueriesData['data']>( FIND_RULES_QUERY_KEY, (currentData) => @@ -122,7 +123,10 @@ export const useUpdateRulesCache = () => { * @param currentRules * @param newRules */ -export function updateRules(currentRules: Rule[], newRules: Rule[]): Rule[] { +export function updateRules( + currentRules: RuleResponse[], + newRules: RuleResponse[] +): RuleResponse[] { const newRulesMap = new Map(newRules.map((rule) => [rule.id, rule])); if (currentRules.some((rule) => newRulesMap.has(rule.id))) { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts index 8f3bd6aef95c0c..5eedf122a6ac6d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/api/hooks/use_update_rule_mutation.ts @@ -6,7 +6,10 @@ */ import type { UseMutationOptions } from '@tanstack/react-query'; import { useMutation } from '@tanstack/react-query'; -import type { RuleUpdateProps } from '../../../../../common/api/detection_engine/model/rule_schema'; +import type { + RuleResponse, + RuleUpdateProps, +} from '../../../../../common/api/detection_engine/model/rule_schema'; import { transformOutput } from '../../../../detections/containers/detection_engine/rules/transforms'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../common/constants'; import { updateRule } from '../api'; @@ -14,19 +17,18 @@ import { useInvalidateFindRulesQuery } from './use_find_rules_query'; import { useUpdateRuleByIdCache } from './use_fetch_rule_by_id_query'; import { useInvalidateFetchRuleManagementFiltersQuery } from './use_fetch_rule_management_filters_query'; import { useInvalidateFetchCoverageOverviewQuery } from './use_fetch_coverage_overview_query'; -import type { Rule } from '../../logic/types'; export const UPDATE_RULE_MUTATION_KEY = ['PUT', DETECTION_ENGINE_RULES_URL]; export const useUpdateRuleMutation = ( - options?: UseMutationOptions + options?: UseMutationOptions ) => { const invalidateFindRulesQuery = useInvalidateFindRulesQuery(); const invalidateFetchRuleManagementFilters = useInvalidateFetchRuleManagementFiltersQuery(); const invalidateFetchCoverageOverviewQuery = useInvalidateFetchCoverageOverviewQuery(); const updateRuleCache = useUpdateRuleByIdCache(); - return useMutation( + return useMutation( (rule: RuleUpdateProps) => updateRule({ rule: transformOutput(rule) }), { ...options, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx index f223214c3c7680..7f1e9cb3203069 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_about_section.tsx @@ -25,7 +25,7 @@ import type { Threats, } from '@kbn/securitysolution-io-ts-alerting-types'; import { ALERT_RISK_SCORE } from '@kbn/rule-data-utils'; -import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; +import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema'; import { SeverityBadge } from '../../../../detections/components/rules/severity_badge'; import { defaultToEmptyTag } from '../../../../common/components/empty_value'; import { filterEmptyThreats } from '../../../rule_creation_ui/pages/rule_creation/helpers'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx index 52d8ad920c9681..2cc3df6bbb827b 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_definition_section.tsx @@ -28,9 +28,13 @@ import { mapAndFlattenFilters } from '@kbn/data-plugin/public'; import { FieldIcon } from '@kbn/react-field'; import { castEsToKbnFieldTypeName } from '@kbn/field-types'; import { FilterBadgeGroup } from '@kbn/unified-search-plugin/public'; -import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; -import type { Threshold as ThresholdType } from '../../../../../common/api/detection_engine/model/rule_schema/specific_attributes/threshold_attributes'; -import type { RequiredFieldArray } from '../../../../../common/api/detection_engine/model/rule_schema/common_attributes'; +import type { + AlertSuppressionMissingFieldsStrategy, + RequiredFieldArray, + RuleResponse, + Threshold as ThresholdType, +} from '../../../../../common/api/detection_engine/model/rule_schema'; +import { AlertSuppressionMissingFieldsStrategyEnum } from '../../../../../common/api/detection_engine/model/rule_schema'; import { assertUnreachable } from '../../../../../common/utility_types'; import * as descriptionStepI18n from '../../../../detections/components/rules/description_step/translations'; import { RelatedIntegrationsDescription } from '../../../../detections/components/rules/related_integrations/integrations_description'; @@ -38,7 +42,6 @@ import { AlertSuppressionTechnicalPreviewBadge } from '../../../../detections/co import { useGetSavedQuery } from '../../../../detections/pages/detection_engine/rules/use_get_saved_query'; import { useLicense } from '../../../../common/hooks/use_license'; import * as threatMatchI18n from '../../../../common/components/threat_match/translations'; -import { AlertSuppressionMissingFieldsStrategy } from '../../../../../common/api/detection_engine/model/rule_schema/specific_attributes/query_attributes'; import * as timelinesI18n from '../../../../timelines/components/timeline/translations'; import { useRuleIndexPattern } from '../../../rule_creation_ui/pages/form'; import { DataSourceType } from '../../../../detections/pages/detection_engine/rules/types'; @@ -348,7 +351,7 @@ interface MissingFieldsStrategyProps { const MissingFieldsStrategy = ({ missingFieldsStrategy }: MissingFieldsStrategyProps) => { const missingFieldsDescription = - missingFieldsStrategy === AlertSuppressionMissingFieldsStrategy.Suppress + missingFieldsStrategy === AlertSuppressionMissingFieldsStrategyEnum.suppress ? descriptionStepI18n.ALERT_SUPPRESSION_SUPPRESS_ON_MISSING_FIELDS : descriptionStepI18n.ALERT_SUPPRESSION_DO_NOT_SUPPRESS_ON_MISSING_FIELDS; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_details_flyout.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_details_flyout.tsx index e4a596f6264bb9..8d20758ac7a8de 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_details_flyout.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_details_flyout.tsx @@ -24,7 +24,7 @@ import { } from '@elastic/eui'; import type { EuiTabbedContentTab, EuiTabbedContentProps } from '@elastic/eui'; -import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; +import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema'; import { RuleOverviewTab, useOverviewTabSections } from './rule_overview_tab'; import { RuleInvestigationGuideTab } from './rule_investigation_guide_tab'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_investigation_guide_tab.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_investigation_guide_tab.tsx index e6d01d1fca588e..e18db2201b364c 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_investigation_guide_tab.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_investigation_guide_tab.tsx @@ -8,7 +8,7 @@ import React from 'react'; import { EuiSpacer } from '@elastic/eui'; import { MarkdownRenderer } from '../../../../common/components/markdown_editor'; -import type { InvestigationGuide } from '../../../../../common/api/detection_engine/model/rule_schema/common_attributes'; +import type { InvestigationGuide } from '../../../../../common/api/detection_engine/model/rule_schema'; interface RuleInvestigationGuideTabProps { note: InvestigationGuide; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_overview_tab.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_overview_tab.tsx index 3d4501bd1f7977..9f8be8c180f94a 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_overview_tab.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_overview_tab.tsx @@ -14,7 +14,7 @@ import { EuiHorizontalRule, useGeneratedHtmlId, } from '@elastic/eui'; -import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; +import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema'; import { RuleAboutSection, Description } from './rule_about_section'; import { RuleDefinitionSection } from './rule_definition_section'; import { RuleScheduleSection } from './rule_schedule_section'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx index 556bd119c52473..5a67b876fe8221 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/components/rule_details/rule_schedule_section.tsx @@ -7,7 +7,7 @@ import React from 'react'; import { EuiDescriptionList, EuiText } from '@elastic/eui'; -import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; +import type { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema'; import { getHumanizedDuration } from '../../../../detections/pages/detection_engine/rules/helpers'; import { DESCRIPTION_LIST_COLUMN_WIDTHS } from './constants'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/mock.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/mock.ts index 6e1c53cb2da210..b8aba73818ac32 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/mock.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/mock.ts @@ -5,10 +5,11 @@ * 2.0. */ -import type { FetchRulesResponse, Rule } from './types'; +import type { RuleResponse } from '../../../../common/api/detection_engine'; +import type { FetchRulesResponse } from './types'; // TODO move to __mocks__ -export const savedRuleMock: Rule = { +export const savedRuleMock: RuleResponse = { author: [], actions: [], created_at: 'mm/dd/yyyyTHH:MM:sssz', @@ -47,9 +48,11 @@ export const savedRuleMock: Rule = { to: 'now', type: 'query', threat: [], - throttle: null, updated_at: 'mm/dd/yyyyTHH:MM:sssz', updated_by: 'mockUser', + version: 1, + revision: 1, + exceptions_list: [], }; export const rulesMock: FetchRulesResponse = { @@ -93,8 +96,9 @@ export const rulesMock: FetchRulesResponse = { to: 'now', type: 'query', threat: [], - throttle: null, version: 1, + revision: 1, + exceptions_list: [], }, { actions: [], @@ -131,8 +135,9 @@ export const rulesMock: FetchRulesResponse = { to: 'now', type: 'query', threat: [], - throttle: null, version: 1, + revision: 1, + exceptions_list: [], }, ], }; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts index 4bb86c26ca7604..d44c4effd265f8 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/types.ts @@ -9,97 +9,23 @@ import * as t from 'io-ts'; import type { RuleSnooze } from '@kbn/alerting-plugin/common'; import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; -import { - RiskScore, - RiskScoreMapping, - RuleActionArray, - RuleActionThrottle, - RuleInterval, - RuleIntervalFrom, - RuleIntervalTo, - Severity, - SeverityMapping, - threat_filters, - threat_index, - threat_indicator_path, - threat_language, - threat_mapping, - threat_query, - type, -} from '@kbn/securitysolution-io-ts-alerting-types'; import type { NamespaceType } from '@kbn/securitysolution-io-ts-list-types'; -import type { RuleSnoozeSettings } from '@kbn/triggers-actions-ui-plugin/public/types'; - import { PositiveInteger } from '@kbn/securitysolution-io-ts-types'; +import type { RuleSnoozeSettings } from '@kbn/triggers-actions-ui-plugin/public/types'; import type { WarningSchema } from '../../../../common/api/detection_engine'; -import { RuleExecutionSummary } from '../../../../common/api/detection_engine/rule_monitoring'; import type { RuleExecutionStatus } from '../../../../common/api/detection_engine/rule_monitoring'; -import { - AlertSuppression, - AlertsIndex, - BuildingBlockType, - DataViewId, - EventCategoryOverride, - ExceptionListArray, - IndexPatternArray, - InvestigationGuide, - IsRuleEnabled, - IsRuleImmutable, - MaxSignals, - RelatedIntegrationArray, - RequiredFieldArray, - RuleAuthorArray, - RuleDescription, - RuleFalsePositiveArray, - RuleFilterArray, - RuleLicense, - RuleName, - RuleNameOverride, - RuleObjectId, - RuleQuery, - RuleReferenceArray, - RuleSignatureId, - RuleTagArray, - RuleVersion, - SavedObjectResolveAliasPurpose, - SavedObjectResolveAliasTargetId, - SavedObjectResolveOutcome, - SetupGuide, - ThreatArray, - Threshold, - TiebreakerField, - TimelineTemplateId, - TimelineTemplateTitle, - TimestampField, - TimestampOverride, - TimestampOverrideFallbackDisabled, - InvestigationFields, -} from '../../../../common/api/detection_engine/model/rule_schema'; +import { SortOrder } from '../../../../common/api/detection_engine'; +import type { + RuleCreateProps, + RuleResponse, + RuleUpdateProps, +} from '../../../../common/api/detection_engine/model/rule_schema'; import type { CoverageOverviewFilter, PatchRuleRequestBody, } from '../../../../common/api/detection_engine/rule_management'; import { FindRulesSortField } from '../../../../common/api/detection_engine/rule_management'; -import type { - RuleCreateProps, - RuleUpdateProps, -} from '../../../../common/api/detection_engine/model/rule_schema'; -import { SortOrder } from '../../../../common/api/detection_engine'; - -/** - * Params is an "record", since it is a type of RuleActionParams which is action templates. - * @see x-pack/plugins/alerting/common/rule.ts - * @deprecated Use the one from @kbn/security-io-ts-alerting-types - */ -export const action = t.exact( - t.type({ - group: t.string, - id: t.string, - action_type_id: t.string, - params: t.record(t.string, t.any), - }) -); export interface CreateRulesProps { rule: RuleCreateProps; @@ -121,95 +47,7 @@ export interface PatchRuleProps { signal?: AbortSignal; } -const MetaRule = t.intersection([ - t.type({ - from: t.string, - }), - t.partial({ - throttle: t.string, - kibana_siem_app_url: t.string, - }), -]); - -export const RuleSchema = t.intersection([ - t.type({ - author: RuleAuthorArray, - created_at: t.string, - created_by: t.string, - description: RuleDescription, - enabled: IsRuleEnabled, - false_positives: RuleFalsePositiveArray, - from: RuleIntervalFrom, - id: RuleObjectId, - interval: RuleInterval, - immutable: IsRuleImmutable, - name: RuleName, - max_signals: MaxSignals, - references: RuleReferenceArray, - related_integrations: RelatedIntegrationArray, - required_fields: RequiredFieldArray, - risk_score: RiskScore, - risk_score_mapping: RiskScoreMapping, - rule_id: RuleSignatureId, - severity: Severity, - severity_mapping: SeverityMapping, - setup: SetupGuide, - tags: RuleTagArray, - type, - to: RuleIntervalTo, - threat: ThreatArray, - updated_at: t.string, - updated_by: t.string, - actions: RuleActionArray, - throttle: t.union([RuleActionThrottle, t.null]), - }), - t.partial({ - outcome: SavedObjectResolveOutcome, - alias_target_id: SavedObjectResolveAliasTargetId, - alias_purpose: SavedObjectResolveAliasPurpose, - building_block_type: BuildingBlockType, - anomaly_threshold: t.number, - filters: RuleFilterArray, - index: IndexPatternArray, - data_view_id: DataViewId, - language: t.string, - license: RuleLicense, - meta: MetaRule, - machine_learning_job_id: t.array(t.string), - new_terms_fields: t.array(t.string), - history_window_start: t.string, - output_index: AlertsIndex, - query: RuleQuery, - rule_name_override: RuleNameOverride, - saved_id: t.string, - threshold: Threshold, - threat_query, - threat_filters, - threat_index, - threat_indicator_path, - threat_mapping, - threat_language, - timeline_id: TimelineTemplateId, - timeline_title: TimelineTemplateTitle, - timestamp_override: TimestampOverride, - timestamp_override_fallback_disabled: TimestampOverrideFallbackDisabled, - event_category_override: EventCategoryOverride, - timestamp_field: TimestampField, - tiebreaker_field: TiebreakerField, - note: InvestigationGuide, - exceptions_list: ExceptionListArray, - uuid: t.string, - version: RuleVersion, - execution_summary: RuleExecutionSummary, - alert_suppression: AlertSuppression, - investigation_fields: InvestigationFields, - }), -]); - -export const RulesSchema = t.array(RuleSchema); - -export type Rule = t.TypeOf; -export type Rules = t.TypeOf; +export type Rule = RuleResponse; export type PaginationOptions = t.TypeOf; export const PaginationOptions = t.type({ @@ -263,7 +101,7 @@ export interface FetchRulesResponse { page: number; perPage: number; total: number; - data: Rule[]; + data: RuleResponse[]; } export interface FetchRuleProps { diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.test.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.test.ts index 99ee0056b5d21b..81438f37086231 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.test.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.test.ts @@ -84,7 +84,7 @@ describe('use_rule_with_fallback', () => { }); }); -const getMockRule = (overwrites: Partial): Rule => ({ +const getMockRule = (overwrites: Pick): Rule => ({ id: 'myfakeruleid', author: [], severity_mapping: [], @@ -97,6 +97,7 @@ const getMockRule = (overwrites: Partial): Rule => ({ name: 'some-name', severity: 'low', type: 'query', + language: 'kuery', query: 'some query', index: ['index-1'], interval: '5m', @@ -107,8 +108,8 @@ const getMockRule = (overwrites: Partial): Rule => ({ max_signals: 100, tags: [], threat: [], - throttle: null, version: 1, + revision: 1, exceptions_list: [], created_at: '2020-04-09T09:43:51.778Z', created_by: 'elastic', diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.ts index 59196fa5264d69..4df58eb3f70f4d 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management/logic/use_rule_with_fallback.ts @@ -8,16 +8,15 @@ import { ALERT_RULE_UUID } from '@kbn/rule-data-utils'; import { isNotFoundError } from '@kbn/securitysolution-t-grid'; import { useEffect, useMemo } from 'react'; -import type { InvestigationFieldsCombined } from '../../../../server/lib/detection_engine/rule_schema'; -import type { InvestigationFields } from '../../../../common/api/detection_engine'; +import type { InvestigationFields, RuleResponse } from '../../../../common/api/detection_engine'; import { expandDottedObject } from '../../../../common/utils/expand_dotted'; +import type { InvestigationFieldsCombined } from '../../../../server/lib/detection_engine/rule_schema'; import { useAppToasts } from '../../../common/hooks/use_app_toasts'; import { ALERTS_QUERY_NAMES } from '../../../detections/containers/detection_engine/alerts/constants'; import type { AlertSearchResponse } from '../../../detections/containers/detection_engine/alerts/types'; import { useQueryAlerts } from '../../../detections/containers/detection_engine/alerts/use_query'; import { transformInput } from '../../../detections/containers/detection_engine/rules/transforms'; import * as i18n from './translations'; -import type { Rule } from './types'; import { useRule } from './use_rule'; interface UseRuleWithFallback { @@ -25,7 +24,7 @@ interface UseRuleWithFallback { loading: boolean; isExistingRule: boolean; refresh: () => void; - rule: Rule | null; + rule: RuleResponse | null; } interface AlertHit { @@ -34,11 +33,11 @@ interface AlertHit { _source: { '@timestamp': string; signal?: { - rule?: Rule; + rule?: RuleResponse; }; kibana?: { alert?: { - rule?: Rule; + rule?: RuleResponse; }; }; }; @@ -96,7 +95,7 @@ export const useRuleWithFallback = (ruleId: string): UseRuleWithFallback => { } }, [addError, error]); - const rule = useMemo(() => { + const rule = useMemo(() => { const result = isExistingRule ? ruleData : alertsData == null @@ -144,7 +143,9 @@ export const migrateLegacyInvestigationFields = ( * @param rule Rule * @returns Rule */ -export const migrateRuleWithLegacyInvestigationFieldsFromAlertHit = (rule: Rule): Rule => { +export const migrateRuleWithLegacyInvestigationFieldsFromAlertHit = ( + rule: RuleResponse +): RuleResponse => { if (!rule) return rule; return { @@ -159,7 +160,7 @@ export const migrateRuleWithLegacyInvestigationFieldsFromAlertHit = (rule: Rule) */ export const transformRuleFromAlertHit = ( data: AlertSearchResponse -): Rule | undefined => { +): RuleResponse | undefined => { // if results empty, return rule as undefined if (data.hits.hits.length === 0) { return undefined; @@ -177,7 +178,7 @@ export const transformRuleFromAlertHit = ( ...expandedRuleWithParams?.kibana?.alert?.rule?.parameters, }; delete expandedRule.parameters; - return migrateRuleWithLegacyInvestigationFieldsFromAlertHit(expandedRule as Rule); + return migrateRuleWithLegacyInvestigationFieldsFromAlertHit(expandedRule as RuleResponse); } return migrateRuleWithLegacyInvestigationFieldsFromAlertHit(rule); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/ml_rule_warning_popover/ml_rule_warning_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/ml_rule_warning_popover/ml_rule_warning_popover.tsx index 7a18a976ab650d..f666b6824a76d6 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/ml_rule_warning_popover/ml_rule_warning_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/ml_rule_warning_popover/ml_rule_warning_popover.tsx @@ -28,6 +28,7 @@ import { getCapitalizedStatusText } from '../../../../detections/components/rule import type { Rule } from '../../../rule_management/logic'; import { isJobStarted } from '../../../../../common/machine_learning/helpers'; import { RuleDetailTabs } from '../../../rule_details_ui/pages/rule_details/use_rule_details_tabs'; +import { getMachineLearningJobId } from '../../../../detections/pages/detection_engine/rules/helpers'; const POPOVER_WIDTH = '340px'; @@ -43,12 +44,12 @@ const MlRuleWarningPopoverComponent: React.FC { const [isPopoverOpen, , closePopover, togglePopover] = useBoolState(); + const jobIds = getMachineLearningJobId(rule); - if (!isMlRule(rule.type) || loadingJobs || !rule.machine_learning_job_id) { + if (!isMlRule(rule.type) || loadingJobs || !jobIds) { return null; } - const jobIds = rule.machine_learning_job_id; const notRunningJobs = jobs.filter( (job) => jobIds.includes(job.id) && !isJobStarted(job.jobState, job.datafeedState) ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts index d525a894a3af4f..86c0e7a1dd133f 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/__mocks__/mock.ts @@ -6,7 +6,6 @@ */ import { FilterStateStore } from '@kbn/es-query'; -import type { Rule } from '../../../../rule_management/logic'; import type { AboutStepRule, ActionsStepRule, @@ -20,6 +19,7 @@ import { import type { FieldValueQueryBar } from '../../../../../detections/components/rules/query_bar'; import { fillEmptySeverityMappings } from '../../../../../detections/pages/detection_engine/rules/helpers'; import { getThreatMock } from '../../../../../../common/detection_engine/schemas/types/threat.mock'; +import type { RuleResponse, SavedQueryRule } from '../../../../../../common/api/detection_engine'; export const mockQueryBar: FieldValueQueryBar = { query: { @@ -51,7 +51,7 @@ export const mockQueryBar: FieldValueQueryBar = { saved_id: 'test123', }; -export const mockRule = (id: string): Rule => ({ +export const mockRule = (id: string): SavedQueryRule => ({ actions: [], author: [], created_at: '2020-01-10T21:11:45.839Z', @@ -92,9 +92,11 @@ export const mockRule = (id: string): Rule => ({ throttle: 'no_actions', note: '# this is some markdown documentation', version: 1, + revision: 1, + exceptions_list: [], }); -export const mockRuleWithEverything = (id: string): Rule => ({ +export const mockRuleWithEverything = (id: string): RuleResponse => ({ actions: [], author: [], created_at: '2020-01-10T21:11:45.839Z', @@ -155,6 +157,7 @@ export const mockRuleWithEverything = (id: string): Rule => ({ to: 'now', type: 'saved_query', threat: getThreatMock(), + // @ts-expect-error This rule stub contains all the fields making it invalid for the RuleResponse type threshold: { field: ['host.name'], value: 50, diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx index 870025a9aa5f8d..1cdda938588477 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/add_prebuilt_rules_table/add_prebuilt_rules_table_context.tsx @@ -19,7 +19,7 @@ import { usePrebuiltRulesInstallReview } from '../../../../rule_management/logic import type { AddPrebuiltRulesTableFilterOptions } from './use_filter_prebuilt_rules_to_install'; import { useFilterPrebuiltRulesToInstall } from './use_filter_prebuilt_rules_to_install'; import { useRuleDetailsFlyout } from '../../../../rule_management/components/rule_details/use_rule_details_flyout'; -import type { RuleResponse } from '../../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; +import type { RuleResponse } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { RuleDetailsFlyout } from '../../../../rule_management/components/rule_details/rule_details_flyout'; import * as i18n from './translations'; diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/ml_rule_warning_popover.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/ml_rule_warning_popover.tsx index 8b0ff0599dbac8..958f8be71fa6be 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/ml_rule_warning_popover.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/ml_rule_warning_popover.tsx @@ -28,6 +28,7 @@ import { getCapitalizedStatusText } from '../../../../detections/components/rule import type { Rule } from '../../../rule_management/logic'; import { isJobStarted } from '../../../../../common/machine_learning/helpers'; import { RuleDetailTabs } from '../../../rule_details_ui/pages/rule_details/use_rule_details_tabs'; +import { getMachineLearningJobId } from '../../../../detections/pages/detection_engine/rules/helpers'; const POPOVER_WIDTH = '340px'; @@ -43,12 +44,12 @@ const MlRuleWarningPopoverComponent: React.FC { const [isPopoverOpen, , closePopover, togglePopover] = useBoolState(); + const jobIds = getMachineLearningJobId(rule); - if (!isMlRule(rule.type) || loadingJobs || !rule.machine_learning_job_id) { + if (!isMlRule(rule.type) || loadingJobs || !jobIds) { return null; } - const jobIds = rule.machine_learning_job_id; const notRunningJobs = jobs.filter( (job) => jobIds.includes(job.id) && !isJobStarted(job.jobState, job.datafeedState) ); diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx index cc975a62be4a0f..3525793caa3a39 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_management_ui/components/rules_table/use_columns.tsx @@ -46,6 +46,7 @@ import { useHasActionsPrivileges } from './use_has_actions_privileges'; import { useHasMlPermissions } from './use_has_ml_permissions'; import { useRulesTableActions } from './use_rules_table_actions'; import { MlRuleWarningPopover } from '../ml_rule_warning_popover/ml_rule_warning_popover'; +import { getMachineLearningJobId } from '../../../../detections/pages/detection_engine/rules/helpers'; export type TableColumn = EuiBasicTableColumn | EuiTableActionsColumnType; @@ -91,7 +92,7 @@ const useEnabledColumn = ({ hasCRUDPermissions, startMlJobs }: ColumnsProps): Ta startMlJobs(rule.machine_learning_job_id)} + startMlJobsIfNeeded={() => startMlJobs(getMachineLearningJobId(rule))} isDisabled={ !canEditRuleWithActions(rule, hasActionsPrivileges) || !hasCRUDPermissions || diff --git a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/get_supported_response_actions.ts b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/get_supported_response_actions.ts index cf195382ec40f6..ad3e3f8392eb11 100644 --- a/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/get_supported_response_actions.ts +++ b/x-pack/plugins/security_solution/public/detection_engine/rule_response_actions/get_supported_response_actions.ts @@ -6,13 +6,14 @@ */ import type { EnabledFeatures } from '@kbn/spaces-plugin/public/management/edit_space/enabled_features'; +import type { ResponseActionTypes } from '../../../common/api/detection_engine/model/rule_response_actions'; import { RESPONSE_ACTION_TYPES, SUPPORTED_RESPONSE_ACTION_TYPES, } from '../../../common/api/detection_engine/model/rule_response_actions'; export interface ResponseActionType { - id: RESPONSE_ACTION_TYPES; + id: ResponseActionTypes; name: string; iconClass: string; disabled?: boolean; diff --git a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx index a04d8d197da1e4..cb20b7910a929a 100644 --- a/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/alerts_table/timeline_actions/alert_context_menu.tsx @@ -37,7 +37,13 @@ import { useAlertsActions } from './use_alerts_actions'; import { useExceptionFlyout } from './use_add_exception_flyout'; import { useAlertExceptionActions } from './use_add_exception_actions'; import { useEventFilterModal } from './use_event_filter_modal'; -import type { Status } from '../../../../../common/api/detection_engine'; +import type { + DataViewId, + IndexPatternArray, + RuleObjectId, + RuleSignatureId, + Status, +} from '../../../../../common/api/detection_engine'; import { ATTACH_ALERT_TO_CASE_FOR_ROW } from '../../../../timelines/components/timeline/body/translations'; import { useEventFilterAction } from './use_event_filter_action'; import { useAddToCaseActions } from './use_add_to_case_actions'; @@ -345,10 +351,10 @@ type AddExceptionFlyoutWrapperProps = Omit< | 'showAlertCloseOptions' > & { eventId?: string; - ruleId: Rule['id']; - ruleRuleId: Rule['rule_id']; - ruleIndices: Rule['index']; - ruleDataViewId: Rule['data_view_id']; + ruleId: RuleObjectId; + ruleRuleId: RuleSignatureId; + ruleIndices: IndexPatternArray | undefined; + ruleDataViewId: DataViewId | undefined; ruleName: Rule['name']; exceptionListType: ExceptionListTypeEnum | null; }; diff --git a/x-pack/plugins/security_solution/public/detections/components/callouts/missing_privileges_callout/translations.tsx b/x-pack/plugins/security_solution/public/detections/components/callouts/missing_privileges_callout/translations.tsx index b3aa96cfc66fd4..0cf89990afc62f 100644 --- a/x-pack/plugins/security_solution/public/detections/components/callouts/missing_privileges_callout/translations.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/callouts/missing_privileges_callout/translations.tsx @@ -75,7 +75,7 @@ export const missingPrivilegesCallOutBody = ({ />

    {indexPrivileges.map(([index, missingPrivileges]) => ( -
  • {missingIndexPrivileges(index, missingPrivileges)}
  • +
  • {missingPrivilegesMessage(index, missingPrivileges)}
  • ))}
@@ -140,6 +140,19 @@ const getPrivilegesExplanation = (missingPrivileges: string[], index: string) => .join(' '); }; +const missingPrivilegesMessage = (index: string, privileges: string[]) => { + // .lists and .items are data streams, so we will show it in the message + if ( + [DEFAULT_LISTS_INDEX, DEFAULT_ITEMS_INDEX].some((dataStreamName) => + index.startsWith(dataStreamName) + ) + ) { + return missingDataStreamPrivileges(index, privileges); + } + + return missingIndexPrivileges(index, privileges); +}; + const missingIndexPrivileges = (index: string, privileges: string[]) => ( ( /> ); +const missingDataStreamPrivileges = (dataStream: string, privileges: string[]) => ( + , + dataStream: {dataStream}, + explanation: getPrivilegesExplanation(privileges, dataStream), + }} + /> +); + const missingFeaturePrivileges = (feature: string, privileges: string[]) => ( ( <> - {!license.isAtLeast(minimumLicenseForSuppression) && ( + {!license.isAtLeast(MINIMUM_LICENSE_FOR_SUPPRESSION) && ( diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx index 0f0779c22f949c..00de6f0a31c4b1 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/helpers.tsx @@ -27,13 +27,17 @@ import { FieldIcon } from '@kbn/react-field'; import type { ThreatMapping, Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { FilterBadgeGroup } from '@kbn/unified-search-plugin/public'; -import type { RequiredFieldArray } from '../../../../../common/api/detection_engine/model/rule_schema/common_attributes'; +import type { + RequiredFieldArray, + Threshold, + AlertSuppressionMissingFieldsStrategy, +} from '../../../../../common/api/detection_engine/model/rule_schema'; +import { AlertSuppressionMissingFieldsStrategyEnum } from '../../../../../common/api/detection_engine/model/rule_schema'; import { MATCHES, AND, OR } from '../../../../common/components/threat_match/translations'; import type { EqlOptionsSelected } from '../../../../../common/search_strategy'; import { assertUnreachable } from '../../../../../common/utility_types'; import * as i18nSeverity from '../severity_mapping/translations'; import * as i18nRiskScore from '../risk_score_mapping/translations'; -import type { Threshold } from '../../../../../common/api/detection_engine/model/rule_schema'; import * as i18n from './translations'; import type { BuildQueryBarDescription, BuildThreatDescription, ListItems } from './types'; @@ -49,7 +53,6 @@ import { ThreatEuiFlexGroup } from './threat_description'; import { AlertSuppressionTechnicalPreviewBadge } from './alert_suppression_technical_preview_badge'; import { TechnicalPreviewBadge } from '../technical_preview_badge'; import type { LicenseService } from '../../../../../common/license'; -import { AlertSuppressionMissingFieldsStrategy } from '../../../../../common/api/detection_engine/model/rule_schema'; const NoteDescriptionContainer = styled(EuiFlexItem)` height: 105px; overflow-y: hidden; @@ -619,7 +622,7 @@ export const buildAlertSuppressionMissingFieldsDescription = ( } const description = - value === AlertSuppressionMissingFieldsStrategy.Suppress + value === AlertSuppressionMissingFieldsStrategyEnum.suppress ? i18n.ALERT_SUPPRESSION_SUPPRESS_ON_MISSING_FIELDS : i18n.ALERT_SUPPRESSION_DO_NOT_SUPPRESS_ON_MISSING_FIELDS; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx index 4fe7b5378b1ce1..58900e1f65a69b 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/description_step/index.tsx @@ -16,7 +16,7 @@ import { FilterManager } from '@kbn/data-plugin/public'; import type { RelatedIntegrationArray, RequiredFieldArray, -} from '../../../../../common/api/detection_engine/model/rule_schema/common_attributes'; +} from '../../../../../common/api/detection_engine/model/rule_schema'; import { buildRelatedIntegrationsDescription } from '../related_integrations/integrations_description'; import { DEFAULT_TIMELINE_TITLE } from '../../../../timelines/components/timeline/translations'; import type { EqlOptionsSelected } from '../../../../../common/search_strategy'; diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx index c0d1db9f837feb..bd5287e04c24b5 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_about_rule_details/index.tsx @@ -21,7 +21,6 @@ import type { PropsWithChildren } from 'react'; import React, { memo, useCallback, useMemo, useState } from 'react'; import { css } from '@emotion/css'; -import type { Rule } from '../../../../detection_engine/rule_management/logic/types'; import { RuleAboutSection } from '../../../../detection_engine/rule_management/components/rule_details/rule_about_section'; import { HeaderSection } from '../../../../common/components/header_section'; import { MarkdownRenderer } from '../../../../common/components/markdown_editor'; @@ -29,9 +28,9 @@ import type { AboutStepRule, AboutStepRuleDetails, } from '../../../pages/detection_engine/rules/types'; -import { castRuleAsRuleResponse } from '../../../../detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response'; import * as i18n from './translations'; import { fullHeight } from './styles'; +import type { RuleResponse } from '../../../../../common/api/detection_engine'; const detailsOption: EuiButtonGroupOptionProps = { id: 'details', @@ -53,7 +52,7 @@ interface StepPanelProps { stepData: AboutStepRule | null; stepDataDetails: AboutStepRuleDetails | null; loading: boolean; - rule: Rule; + rule: RuleResponse; } const StepAboutRuleToggleDetailsComponent: React.FC = ({ @@ -128,11 +127,7 @@ const StepAboutRuleToggleDetailsComponent: React.FC = ({ - + )} diff --git a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx index 90ba699131625e..3fb473204feea3 100644 --- a/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx +++ b/x-pack/plugins/security_solution/public/detections/components/rules/step_define_rule/index.tsx @@ -79,11 +79,9 @@ import { DocLink } from '../../../../common/components/links_to_docs/doc_link'; import { defaultCustomQuery } from '../../../pages/detection_engine/rules/utils'; import { MultiSelectFieldsAutocomplete } from '../multi_select_fields'; import { useLicense } from '../../../../common/hooks/use_license'; -import { - minimumLicenseForSuppression, - AlertSuppressionMissingFieldsStrategy, -} from '../../../../../common/api/detection_engine/model/rule_schema'; +import { AlertSuppressionMissingFieldsStrategyEnum } from '../../../../../common/api/detection_engine/model/rule_schema'; import { DurationInput } from '../duration_input'; +import { MINIMUM_LICENSE_FOR_SUPPRESSION } from '../../../../../common/detection_engine/constants'; const CommonUseField = getUseField({ component: Field }); @@ -419,7 +417,7 @@ const StepDefineRuleComponent: FC = ({ ({ groupByRadioSelection, groupByDurationUnit, groupByDurationValue }) => ( = ({ durationValueField={groupByDurationValue} durationUnitField={groupByDurationUnit} isDisabled={ - !license.isAtLeast(minimumLicenseForSuppression) || + !license.isAtLeast(MINIMUM_LICENSE_FOR_SUPPRESSION) || groupByFields?.length === 0 || groupByRadioSelection.value !== GroupByOptions.PerTimePeriod } @@ -461,18 +459,18 @@ const StepDefineRuleComponent: FC = ({ ({ suppressionMissingFields }) => ( = ({ browserFields: termsAggregationFields, disabledText: i18n.GROUP_BY_FIELD_LICENSE_WARNING, isDisabled: - !license.isAtLeast(minimumLicenseForSuppression) && groupByFields?.length === 0, + !license.isAtLeast(MINIMUM_LICENSE_FOR_SUPPRESSION) && + groupByFields?.length === 0, }} /> diff --git a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/transforms.ts b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/transforms.ts index 9ceff56313f298..38eaeedc44f26b 100644 --- a/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/transforms.ts +++ b/x-pack/plugins/security_solution/public/detections/containers/detection_engine/rules/transforms.ts @@ -9,9 +9,9 @@ import { flow } from 'fp-ts/lib/function'; import { addIdToItem, removeIdFromItem } from '@kbn/securitysolution-utils'; import type { RuleCreateProps, + RuleResponse, RuleUpdateProps, } from '../../../../../common/api/detection_engine/model/rule_schema'; -import type { Rule } from '../../../../detection_engine/rule_management/logic/types'; // These are a collection of transforms that are UI specific and useful for UI concerns // that are inserted between the API and the actual user interface. In some ways these @@ -45,7 +45,7 @@ export const transformOutput = ( * @param rule The rule to transform the output of * @returns The rule transformed from the output */ -export const transformInput = (rule: Rule): Rule => flow(addIdToThreatMatchArray)(rule); +export const transformInput = (rule: RuleResponse): RuleResponse => addIdToThreatMatchArray(rule); /** * This adds an id to the incoming threat match arrays as ReactJS prefers to have @@ -62,7 +62,7 @@ export const transformInput = (rule: Rule): Rule => flow(addIdToThreatMatchArray * @param rule The rule to add an id to the threat matches. * @returns rule The rule but with id added to the threat array and entries */ -export const addIdToThreatMatchArray = (rule: Rule): Rule => { +export const addIdToThreatMatchArray = (rule: RuleResponse): RuleResponse => { if (rule.type === 'threat_match' && rule.threat_mapping != null) { const threatMapWithId = rule.threat_mapping.map((mapping) => { const newEntries = mapping.entries.map((entry) => addIdToItem(entry)); diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx index 517a30df5acf05..b401e2a1fe944e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.test.tsx @@ -24,7 +24,8 @@ import { mockRule, } from '../../../../detection_engine/rule_management_ui/components/rules_table/__mocks__/mock'; import { FilterStateStore } from '@kbn/es-query'; -import { AlertSuppressionMissingFieldsStrategy } from '../../../../../common/api/detection_engine/model/rule_schema'; +import type { RuleAction } from '../../../../../common/api/detection_engine/model/rule_schema'; +import { AlertSuppressionMissingFieldsStrategyEnum } from '../../../../../common/api/detection_engine/model/rule_schema'; import type { Rule } from '../../../../detection_engine/rule_management/logic'; import type { @@ -35,7 +36,6 @@ import type { ActionsStepRule, } from './types'; import { getThreatMock } from '../../../../../common/detection_engine/schemas/types/threat.mock'; -import type { RuleAlertAction } from '../../../../../common/detection_engine/types'; describe('rule helpers', () => { moment.suppressDeprecationWarnings = true; @@ -251,9 +251,8 @@ describe('rule helpers', () => { }); test('returns with saved_id of undefined if value does not exist on rule', () => { - const mockedRule = { - ...mockRule('test-id'), - }; + const mockedRule = mockRule('test-id'); + // @ts-expect-error Saved query rule requires saved_id delete mockedRule.saved_id; const result: DefineStepRule = getDefineStepsData(mockedRule); const expected = expect.objectContaining({ @@ -286,7 +285,7 @@ describe('rule helpers', () => { test('returns default suppress value in suppress strategy is missing', () => { const result: DefineStepRule = getDefineStepsData(mockRule('test-id')); const expected = expect.objectContaining({ - suppressionMissingFields: AlertSuppressionMissingFieldsStrategy.Suppress, + suppressionMissingFields: AlertSuppressionMissingFieldsStrategyEnum.suppress, }); expect(result).toEqual(expected); @@ -297,11 +296,11 @@ describe('rule helpers', () => { ...mockRule('test-id'), alert_suppression: { group_by: [], - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }, }); const expected = expect.objectContaining({ - suppressionMissingFields: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + suppressionMissingFields: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }); expect(result).toEqual(expected); @@ -370,7 +369,7 @@ describe('rule helpers', () => { describe('getActionsStepsData', () => { test('returns expected ActionsStepRule rule object', () => { - const actions: RuleAlertAction[] = [ + const actions: RuleAction[] = [ { id: 'id', group: 'group', diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx index 4beff423fd1f87..3acccc3352a414 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/helpers.tsx @@ -23,14 +23,11 @@ import type { Filter } from '@kbn/es-query'; import type { ActionVariables } from '@kbn/triggers-actions-ui-plugin/public'; import type { ResponseAction } from '../../../../../common/api/detection_engine/model/rule_response_actions'; import { normalizeThresholdField } from '../../../../../common/detection_engine/utils'; -import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../common/api/detection_engine/model/rule_schema'; -import type { RuleAlertAction } from '../../../../../common/detection_engine/types'; import { assertUnreachable } from '../../../../../common/utility_types'; import { transformRuleToAlertAction, transformRuleToAlertResponseAction, } from '../../../../../common/detection_engine/transform_actions'; -import type { Rule } from '../../../../detection_engine/rule_management/logic'; import type { AboutStepRule, AboutStepRuleDetails, @@ -40,6 +37,8 @@ import type { } from './types'; import { DataSourceType, GroupByOptions } from './types'; import { severityOptions } from '../../../components/rules/step_about_rule/data'; +import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../common/detection_engine/constants'; +import type { RuleAction, RuleResponse } from '../../../../../common/api/detection_engine'; export interface GetStepsData { aboutRuleData: AboutStepRule; @@ -53,7 +52,7 @@ export const getStepsData = ({ rule, detailsView = false, }: { - rule: Rule; + rule: RuleResponse; detailsView?: boolean; }): GetStepsData => { const defineRuleData: DefineStepRule = getDefineStepsData(rule); @@ -72,39 +71,55 @@ export const getStepsData = ({ }; export const getActionsStepsData = ( - rule: Omit & { - actions: RuleAlertAction[]; + rule: Omit & { + actions: RuleAction[]; response_actions?: ResponseAction[]; } ): ActionsStepRule => { const { enabled, meta, actions = [], response_actions: responseActions } = rule; return { - actions: actions?.map(transformRuleToAlertAction), + actions: actions?.map((action) => transformRuleToAlertAction(action)), responseActions: responseActions?.map(transformRuleToAlertResponseAction), - kibanaSiemAppUrl: meta?.kibana_siem_app_url, + kibanaSiemAppUrl: + typeof meta?.kibana_siem_app_url === 'string' ? meta.kibana_siem_app_url : undefined, enabled, }; }; +export const getMachineLearningJobId = (rule: RuleResponse): string[] | undefined => { + if (rule.type === 'machine_learning') { + return typeof rule.machine_learning_job_id === 'string' + ? [rule.machine_learning_job_id] + : rule.machine_learning_job_id; + } + return undefined; +}; + /* eslint-disable complexity */ -export const getDefineStepsData = (rule: Rule): DefineStepRule => ({ +export const getDefineStepsData = (rule: RuleResponse): DefineStepRule => ({ ruleType: rule.type, - anomalyThreshold: rule.anomaly_threshold ?? 50, - machineLearningJobId: rule.machine_learning_job_id ?? [], - index: rule.index ?? [], - dataViewId: rule.data_view_id, - threatIndex: rule.threat_index ?? [], + anomalyThreshold: 'anomaly_threshold' in rule ? rule.anomaly_threshold : 50, + machineLearningJobId: getMachineLearningJobId(rule) || [], + index: ('index' in rule && rule.index) || [], + dataViewId: 'data_view_id' in rule ? rule.data_view_id : undefined, + threatIndex: ('threat_index' in rule && rule.threat_index) || [], threatQueryBar: { - query: { query: rule.threat_query ?? '', language: rule.threat_language ?? '' }, - filters: (rule.threat_filters ?? []) as Filter[], + query: { + query: ('threat_query' in rule && rule.threat_query) || '', + language: ('threat_language' in rule && rule.threat_language) || '', + }, + filters: (('threat_filters' in rule && rule.threat_filters) || []) as Filter[], saved_id: null, }, - threatMapping: rule.threat_mapping ?? [], + threatMapping: ('threat_mapping' in rule && rule.threat_mapping) || [], queryBar: { - query: { query: rule.query ?? '', language: rule.language ?? '' }, - filters: (rule.filters ?? []) as Filter[], - saved_id: rule.saved_id ?? null, + query: { + query: ('query' in rule && rule.query) || '', + language: ('language' in rule && rule.language) || '', + }, + filters: (('filters' in rule && rule.filters) || []) as Filter[], + saved_id: ('saved_id' in rule && rule.saved_id) || null, }, relatedIntegrations: rule.related_integrations ?? [], requiredFields: rule.required_fields ?? [], @@ -113,9 +128,9 @@ export const getDefineStepsData = (rule: Rule): DefineStepRule => ({ title: rule.timeline_title ?? null, }, threshold: { - field: normalizeThresholdField(rule.threshold?.field), - value: `${rule.threshold?.value || 100}`, - ...(rule.threshold?.cardinality?.length + field: normalizeThresholdField('threshold' in rule ? rule.threshold?.field : undefined), + value: `${('threshold' in rule && rule.threshold?.value) || 100}`, + ...('threshold' in rule && rule.threshold?.cardinality?.length ? { cardinality: { field: [`${rule.threshold.cardinality[0].field}`], @@ -125,23 +140,33 @@ export const getDefineStepsData = (rule: Rule): DefineStepRule => ({ : {}), }, eqlOptions: { - timestampField: rule.timestamp_field, - eventCategoryField: rule.event_category_override, - tiebreakerField: rule.tiebreaker_field, + timestampField: 'timestamp_field' in rule ? rule.timestamp_field : undefined, + eventCategoryField: + 'event_category_override' in rule ? rule.event_category_override : undefined, + tiebreakerField: 'tiebreaker_field' in rule ? rule.tiebreaker_field : undefined, }, - dataSourceType: rule.data_view_id ? DataSourceType.DataView : DataSourceType.IndexPatterns, - newTermsFields: rule.new_terms_fields ?? [], - historyWindowSize: rule.history_window_start - ? convertHistoryStartToSize(rule.history_window_start) - : '7d', + dataSourceType: + 'data_view_id' in rule && rule.data_view_id + ? DataSourceType.DataView + : DataSourceType.IndexPatterns, + newTermsFields: ('new_terms_fields' in rule && rule.new_terms_fields) || [], + historyWindowSize: + 'history_window_start' in rule && rule.history_window_start + ? convertHistoryStartToSize(rule.history_window_start) + : '7d', shouldLoadQueryDynamically: Boolean(rule.type === 'saved_query' && rule.saved_id), - groupByFields: rule.alert_suppression?.group_by ?? [], - groupByRadioSelection: rule.alert_suppression?.duration - ? GroupByOptions.PerTimePeriod - : GroupByOptions.PerRuleExecution, - groupByDuration: rule.alert_suppression?.duration ?? { value: 5, unit: 'm' }, + groupByFields: ('alert_suppression' in rule && rule.alert_suppression?.group_by) || [], + groupByRadioSelection: + 'alert_suppression' in rule && rule.alert_suppression?.duration + ? GroupByOptions.PerTimePeriod + : GroupByOptions.PerRuleExecution, + groupByDuration: ('alert_suppression' in rule && rule.alert_suppression?.duration) || { + value: 5, + unit: 'm', + }, suppressionMissingFields: - rule.alert_suppression?.missing_fields_strategy ?? DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY, + ('alert_suppression' in rule && rule.alert_suppression?.missing_fields_strategy) || + DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY, }); export const convertHistoryStartToSize = (relativeTime: string) => { @@ -152,7 +177,7 @@ export const convertHistoryStartToSize = (relativeTime: string) => { } }; -export const getScheduleStepsData = (rule: Rule): ScheduleStepRule => { +export const getScheduleStepsData = (rule: RuleResponse): ScheduleStepRule => { const { interval, from } = rule; const fromHumanizedValue = getHumanizedDuration(from, interval); @@ -184,7 +209,7 @@ export const getHumanizedDuration = (from: string, interval: string): string => } }; -export const getAboutStepsData = (rule: Rule, detailsView: boolean): AboutStepRule => { +export const getAboutStepsData = (rule: RuleResponse, detailsView: boolean): AboutStepRule => { const { name, description, note } = determineDetailsValue(rule, detailsView); const { author, @@ -203,8 +228,9 @@ export const getAboutStepsData = (rule: Rule, detailsView: boolean): AboutStepRu investigation_fields: investigationFields, tags, threat, - threat_indicator_path: threatIndicatorPath, } = rule; + const threatIndicatorPath = + 'threat_indicator_path' in rule ? rule.threat_indicator_path : undefined; return { author, @@ -256,9 +282,9 @@ export const fillEmptySeverityMappings = (mappings: SeverityMapping): SeverityMa }; export const determineDetailsValue = ( - rule: Rule, + rule: RuleResponse, detailsView: boolean -): Pick => { +): Pick => { const { name, description, note } = rule; if (detailsView) { return { name: '', description: '', note: '' }; @@ -267,7 +293,7 @@ export const determineDetailsValue = ( return { name, description, note: note ?? '' }; }; -export const getModifiedAboutDetailsData = (rule: Rule): AboutStepRuleDetails => ({ +export const getModifiedAboutDetailsData = (rule: RuleResponse): AboutStepRuleDetails => ({ note: rule.note ?? '', description: rule.description, setup: rule.setup ?? '', diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts index 0d03c43d3ada5d..8b9fb30a4c1ba2 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/types.ts @@ -17,10 +17,9 @@ import type { Type, } from '@kbn/securitysolution-io-ts-alerting-types'; import type { DataViewBase, Filter } from '@kbn/es-query'; -import type { RuleAction } from '@kbn/alerting-plugin/common'; +import type { RuleAction as AlertingRuleAction } from '@kbn/alerting-plugin/common'; import type { DataViewListItem } from '@kbn/data-views-plugin/common'; -import type { RuleAlertAction } from '../../../../../common/detection_engine/types'; import type { FieldValueQueryBar } from '../../../components/rules/query_bar'; import type { FieldValueTimeline } from '../../../components/rules/pick_timeline'; import type { FieldValueThreshold } from '../../../components/rules/threshold_input'; @@ -33,8 +32,9 @@ import type { RuleNameOverride, SetupGuide, TimestampOverride, - AlertSuppressionMissingFields, + AlertSuppressionMissingFieldsStrategy, InvestigationFields, + RuleAction, } from '../../../../../common/api/detection_engine/model/rule_schema'; import type { SortOrder } from '../../../../../common/api/detection_engine'; import type { EqlOptionsSelected } from '../../../../../common/search_strategy'; @@ -157,7 +157,7 @@ export interface DefineStepRule { groupByFields: string[]; groupByRadioSelection: GroupByOptions; groupByDuration: Duration; - suppressionMissingFields?: AlertSuppressionMissingFields; + suppressionMissingFields?: AlertSuppressionMissingFieldsStrategy; } export interface QueryDefineStep { @@ -184,7 +184,7 @@ export interface ScheduleStepRule { } export interface ActionsStepRule { - actions: RuleAction[]; + actions: AlertingRuleAction[]; responseActions?: RuleResponseAction[]; enabled: boolean; kibanaSiemAppUrl?: string; @@ -251,7 +251,7 @@ export interface ScheduleStepRuleJson { } export interface ActionsStepRuleJson { - actions: RuleAlertAction[]; + actions: RuleAction[]; response_actions?: ResponseAction[]; enabled: boolean; throttle?: string | null; diff --git a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts index 9b1aac51e3689c..56076f54b4817e 100644 --- a/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts +++ b/x-pack/plugins/security_solution/public/detections/pages/detection_engine/rules/utils.ts @@ -9,9 +9,9 @@ import type { Type } from '@kbn/securitysolution-io-ts-alerting-types'; import { isThreatMatchRule } from '../../../../../common/detection_engine/utils'; import { DEFAULT_TIMELINE_TITLE } from '../../../../timelines/components/timeline/translations'; import { DEFAULT_THREAT_MATCH_QUERY } from '../../../../../common/constants'; +import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../common/detection_engine/constants'; import type { AboutStepRule, DefineStepRule, RuleStepsOrder, ScheduleStepRule } from './types'; import { DataSourceType, GroupByOptions, RuleStep } from './types'; -import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../common/api/detection_engine/model/rule_schema'; import { fillEmptySeverityMappings } from './helpers'; export const ruleStepsOrder: RuleStepsOrder = [ diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview.tsx index c5e862b3f7a0f7..6e4d9221421ee3 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview.tsx @@ -8,7 +8,6 @@ import React, { memo, useState, useEffect } from 'react'; import { EuiText, EuiHorizontalRule, EuiSpacer, EuiPanel } from '@elastic/eui'; import { css } from '@emotion/css'; import { FormattedMessage } from '@kbn/i18n-react'; -import type { Rule } from '../../../../detection_engine/rule_management/logic'; import { usePreviewPanelContext } from '../context'; import { ExpandableSection } from '../../right/components/expandable_section'; import { useRuleWithFallback } from '../../../../detection_engine/rule_management/logic/use_rule_with_fallback'; @@ -18,7 +17,6 @@ import { RuleAboutSection } from '../../../../detection_engine/rule_management/c import { RuleScheduleSection } from '../../../../detection_engine/rule_management/components/rule_details/rule_schedule_section'; import { RuleDefinitionSection } from '../../../../detection_engine/rule_management/components/rule_details/rule_definition_section'; import { StepRuleActionsReadOnly } from '../../../../detections/components/rules/step_rule_actions'; -import { castRuleAsRuleResponse } from '../../../../detection_engine/rule_details_ui/pages/rule_details/cast_rule_as_rule_response'; import { FlyoutLoading } from '../../../shared/components/flyout_loading'; import { FlyoutError } from '../../../shared/components/flyout_error'; import { @@ -29,6 +27,7 @@ import { RULE_PREVIEW_ACTIONS_TEST_ID, RULE_PREVIEW_LOADING_TEST_ID, } from './test_ids'; +import type { RuleResponse } from '../../../../../common/api/detection_engine'; const panelViewStyle = css` dt { @@ -42,7 +41,7 @@ const panelViewStyle = css` */ export const RulePreview: React.FC = memo(() => { const { ruleId } = usePreviewPanelContext(); - const [rule, setRule] = useState(null); + const [rule, setRule] = useState(null); const { rule: maybeRule, loading: ruleLoading, @@ -88,7 +87,7 @@ export const RulePreview: React.FC = memo(() => { {rule.description} { data-test-subj={RULE_PREVIEW_DEFINITION_TEST_ID} > { expanded={false} data-test-subj={RULE_PREVIEW_SCHEDULE_TEST_ID} > - + {hasActions && ( diff --git a/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview_title.tsx b/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview_title.tsx index 9ea1564b9bcd0d..c04dde6b82a45a 100644 --- a/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview_title.tsx +++ b/x-pack/plugins/security_solution/public/flyout/document_details/preview/components/rule_preview_title.tsx @@ -8,7 +8,6 @@ import React from 'react'; import { EuiTitle, EuiText, EuiSpacer, EuiFlexGroup, EuiFlexItem, EuiBadge } from '@elastic/eui'; import { DELETED_RULE } from '../../../../detection_engine/rule_details_ui/pages/rule_details/translations'; -import type { Rule } from '../../../../detection_engine/rule_management/logic'; import { CreatedBy, UpdatedBy } from '../../../../detections/components/rules/rule_info'; import { RULE_PREVIEW_TITLE_TEST_ID, @@ -16,12 +15,13 @@ import { RULE_PREVIEW_RULE_UPDATED_BY_TEST_ID, RULE_PREVIEW_RULE_TITLE_SUPPRESSED_TEST_ID, } from './test_ids'; +import type { RuleResponse } from '../../../../../common/api/detection_engine'; export interface RulePreviewTitleProps { /** * Rule object that represents relevant information about a rule */ - rule: Rule; + rule: RuleResponse; /** * Flag to indicate if rule is suppressed */ diff --git a/x-pack/plugins/security_solution/server/endpoint/lib/metadata/check_metadata_transforms_task.ts b/x-pack/plugins/security_solution/server/endpoint/lib/metadata/check_metadata_transforms_task.ts index c36fcbec8b879e..d86d8e41fb05ae 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/metadata/check_metadata_transforms_task.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/metadata/check_metadata_transforms_task.ts @@ -26,7 +26,7 @@ import { import { WARNING_TRANSFORM_STATES } from '../../../../common/constants'; import { wrapErrorIfNeeded } from '../../utils'; import { stateSchemaByVersion, emptyState, type LatestTaskStateSchema } from './task_state'; -import { isEndpointPackageV2 } from '../../../../common/endpoint/utils/transforms'; +import { isEndpointPackageV2 } from '../../../../common/endpoint/utils/package_v2'; const SCOPE = ['securitySolution']; const INTERVAL = '2h'; diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts index 93593efef13444..6641a148d49a1e 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/handlers.ts @@ -29,7 +29,7 @@ import { METADATA_TRANSFORMS_PATTERN, METADATA_TRANSFORMS_PATTERN_V2, } from '../../../../common/endpoint/constants'; -import { isEndpointPackageV2 } from '../../../../common/endpoint/utils/transforms'; +import { isEndpointPackageV2 } from '../../../../common/endpoint/utils/package_v2'; export const getLogger = (endpointAppContext: EndpointAppContext): Logger => { return endpointAppContext.logFactory.get('metadata'); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts index a383cc2ad92a9b..b0d53f2c43a9db 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/api/review_rule_upgrade/review_rule_upgrade_route.ts @@ -15,7 +15,7 @@ import type { ThreeWayDiff, } from '../../../../../../common/api/detection_engine/prebuilt_rules'; import { invariant } from '../../../../../../common/utils/invariant'; -import type { RuleResponse } from '../../../../../../common/api/detection_engine/model/rule_schema/rule_schemas'; +import type { RuleResponse } from '../../../../../../common/api/detection_engine/model/rule_schema'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; import { buildSiemResponse } from '../../../routes/utils'; import type { CalculateRuleDiffResult } from '../../logic/diff/calculate_rule_diff'; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/normalization/convert_rule_to_diffable.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/normalization/convert_rule_to_diffable.ts index de90b88f6b0232..e4101465055450 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/normalization/convert_rule_to_diffable.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/diff/normalization/convert_rule_to_diffable.ts @@ -5,6 +5,7 @@ * 2.0. */ +import type { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types'; import { DEFAULT_MAX_SIGNALS } from '../../../../../../../common/constants'; import { assertUnreachable } from '../../../../../../../common/utility_types'; import type { @@ -137,7 +138,7 @@ const extractDiffableCommonFields = ( // Other domain fields rule_schedule: extractRuleSchedule(rule), - actions: rule.actions ?? [], + actions: (rule.actions ?? []) as RuleActionArray, throttle: rule.throttle ?? 'no_actions', exceptions_list: rule.exceptions_list ?? [], max_signals: rule.max_signals ?? DEFAULT_MAX_SIGNALS, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_assets/prebuilt_rule_assets_validation.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_assets/prebuilt_rule_assets_validation.ts index 6ba2417fc5263e..fd69ac51a0f402 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_assets/prebuilt_rule_assets_validation.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/logic/rule_assets/prebuilt_rule_assets_validation.ts @@ -4,11 +4,8 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import type * as t from 'io-ts'; -import { getOrElse } from 'fp-ts/lib/Either'; +import { stringifyZodError } from '@kbn/zod-helpers'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; -import { exactCheck, formatErrors } from '@kbn/securitysolution-io-ts-utils'; import { PrebuiltRuleAsset } from '../../model/rule_assets/prebuilt_rule_asset'; export const validatePrebuiltRuleAssets = (rules: PrebuiltRuleAsset[]): PrebuiltRuleAsset[] => { @@ -16,21 +13,20 @@ export const validatePrebuiltRuleAssets = (rules: PrebuiltRuleAsset[]): Prebuilt }; export const validatePrebuiltRuleAsset = (rule: PrebuiltRuleAsset): PrebuiltRuleAsset => { - const decoded = PrebuiltRuleAsset.decode(rule); - const checked = exactCheck(rule, decoded); + const result = PrebuiltRuleAsset.safeParse(rule); - const onLeft = (errors: t.Errors): PrebuiltRuleAsset => { + if (!result.success) { const ruleName = rule.name ? rule.name : '(rule name unknown)'; const ruleId = rule.rule_id ? rule.rule_id : '(rule rule_id unknown)'; throw new BadRequestError( `name: "${ruleName}", rule_id: "${ruleId}" within the security-rule saved object ` + `is not a valid detection engine rule. Expect the system ` + `to not work with pre-packaged rules until this rule is fixed ` + - `or the file is removed. Error is: ${formatErrors( - errors - ).join()}, Full rule contents are:\n${JSON.stringify(rule, null, 2)}` + `or the file is removed. Error is: ${stringifyZodError( + result.error + )}, Full rule contents are:\n${JSON.stringify(rule, null, 2)}` ); - }; + } - return getOrElse(onLeft)(checked); + return result.data; }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts index 7960167a993efd..73350b48941dbf 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.test.ts @@ -5,12 +5,8 @@ * 2.0. */ -import { left } from 'fp-ts/lib/Either'; -import { pipe } from 'fp-ts/lib/pipeable'; -import { exactCheck, foldLeftRight, getPaths } from '@kbn/securitysolution-io-ts-utils'; - +import { expectParseError, expectParseSuccess, stringifyZodError } from '@kbn/zod-helpers'; import { getListArrayMock } from '../../../../../../common/detection_engine/schemas/types/lists.mock'; - import { PrebuiltRuleAsset } from './prebuilt_rule_asset'; import { getPrebuiltRuleMock, getPrebuiltThreatMatchRuleMock } from './prebuilt_rule_asset.mock'; @@ -18,41 +14,22 @@ describe('Prebuilt rule asset schema', () => { test('empty objects do not validate', () => { const payload: Partial = {}; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "description"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "name"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "severity"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "rule_id"' + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"name: Required, description: Required, risk_score: Required, severity: Required, Invalid input, rule_id: Required, version: Required"` ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "version"' - ); - expect(message.schema).toEqual({}); }); - test('made up values do not validate', () => { + test('made up values get omitted', () => { const payload: PrebuiltRuleAsset & { madeUp: string } = { ...getPrebuiltRuleMock(), madeUp: 'hi', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "madeUp"']); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(getPrebuiltRuleMock()); }); test('[rule_id] does not validate', () => { @@ -60,308 +37,11 @@ describe('Prebuilt rule asset schema', () => { rule_id: 'rule-1', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "description"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "name"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "severity"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "version"' - ); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "name"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "severity"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "version"' - ); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "name"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "severity"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "version"' - ); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from, to] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "name"' + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"name: Required, description: Required, risk_score: Required, severity: Required, Invalid input, version: Required"` ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "severity"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "version"' - ); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from, to, name] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "severity"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "version"' - ); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from, to, name, severity] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "risk_score"' - ); - expect(getPaths(left(message.errors))).toContain( - 'Invalid value "undefined" supplied to "version"' - ); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from, to, name, severity, type] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - type: 'query', - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - 'Invalid value "undefined" supplied to "version"', - ]); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from, to, name, severity, type, interval] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - 'Invalid value "undefined" supplied to "version"', - ]); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from, to, name, severity, type, interval, index] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - type: 'query', - interval: '5m', - index: ['index-1'], - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "risk_score"', - 'Invalid value "undefined" supplied to "version"', - ]); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from, to, name, severity, type, query, index, interval, version] does validate', () => { - const payload: PrebuiltRuleAsset = { - rule_id: 'rule-1', - risk_score: 50, - description: 'some description', - from: 'now-5m', - to: 'now', - name: 'some-name', - severity: 'low', - type: 'query', - query: 'some query', - index: ['index-1'], - interval: '5m', - version: 1, - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - }); - - test('[rule_id, description, from, to, index, name, severity, interval, type, query, language] does not validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - query: 'some query', - language: 'kuery', - risk_score: 50, - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "version"', - ]); - expect(message.schema).toEqual({}); - }); - - test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, version] does validate', () => { - const payload: Partial = { - rule_id: 'rule-1', - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - query: 'some query', - language: 'kuery', - risk_score: 50, - version: 1, - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); - }); - - test('[rule_id, description, from, to, index, name, severity, interval, type, query, language, risk_score, output_index] does not validate', () => { - const payload: Partial & { output_index: string } = { - rule_id: 'rule-1', - output_index: '.siem-signals', - risk_score: 50, - description: 'some description', - from: 'now-5m', - to: 'now', - index: ['index-1'], - name: 'some-name', - severity: 'low', - interval: '5m', - type: 'query', - query: 'some query', - language: 'kuery', - }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "version"', - ]); - expect(message.schema).toEqual({}); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, version] does validate', () => { @@ -379,10 +59,9 @@ describe('Prebuilt rule asset schema', () => { version: 1, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can send in a namespace', () => { @@ -391,10 +70,9 @@ describe('Prebuilt rule asset schema', () => { namespace: 'a namespace', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can send in an empty array to threat', () => { @@ -403,10 +81,9 @@ describe('Prebuilt rule asset schema', () => { threat: [], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, output_index, threat] does validate', () => { @@ -441,10 +118,9 @@ describe('Prebuilt rule asset schema', () => { version: 1, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('allows references to be sent as valid', () => { @@ -453,23 +129,20 @@ describe('Prebuilt rule asset schema', () => { references: ['index-1'], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); - test('immutable cannot be set in a pre-packaged rule', () => { + test('immutable is omitted from a pre-packaged rule', () => { const payload: PrebuiltRuleAsset & { immutable: boolean } = { ...getPrebuiltRuleMock(), immutable: true, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['invalid keys "immutable"']); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(getPrebuiltRuleMock()); }); test('rule_id is required', () => { @@ -477,13 +150,9 @@ describe('Prebuilt rule asset schema', () => { // @ts-expect-error delete payload.rule_id; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "rule_id"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"rule_id: Required"`); }); test('references cannot be numbers', () => { @@ -492,11 +161,11 @@ describe('Prebuilt rule asset schema', () => { references: [5], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "references"']); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"references.0: Expected string, received number"` + ); }); test('indexes cannot be numbers', () => { @@ -505,11 +174,9 @@ describe('Prebuilt rule asset schema', () => { index: [5], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "5" supplied to "index"']); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('saved_query type can have filters with it', () => { @@ -518,10 +185,9 @@ describe('Prebuilt rule asset schema', () => { filters: [], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('filters cannot be a string', () => { @@ -530,13 +196,9 @@ describe('Prebuilt rule asset schema', () => { filters: 'some string', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "some string" supplied to "filters"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('language validates with kuery', () => { @@ -545,10 +207,9 @@ describe('Prebuilt rule asset schema', () => { language: 'kuery', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('language validates with lucene', () => { @@ -557,10 +218,9 @@ describe('Prebuilt rule asset schema', () => { language: 'lucene', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('language does not validate with something made up', () => { @@ -569,13 +229,9 @@ describe('Prebuilt rule asset schema', () => { language: 'something-made-up', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "something-made-up" supplied to "language"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"Invalid input"`); }); test('max_signals cannot be negative', () => { @@ -584,13 +240,11 @@ describe('Prebuilt rule asset schema', () => { max_signals: -1, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "-1" supplied to "max_signals"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"max_signals: Number must be greater than or equal to 1"` + ); }); test('max_signals cannot be zero', () => { @@ -599,11 +253,11 @@ describe('Prebuilt rule asset schema', () => { max_signals: 0, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "0" supplied to "max_signals"']); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"max_signals: Number must be greater than or equal to 1"` + ); }); test('max_signals can be 1', () => { @@ -612,10 +266,9 @@ describe('Prebuilt rule asset schema', () => { max_signals: 1, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can optionally send in an array of tags', () => { @@ -624,10 +277,9 @@ describe('Prebuilt rule asset schema', () => { tags: ['tag_1', 'tag_2'], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot send in an array of tags that are numbers', () => { @@ -636,15 +288,11 @@ describe('Prebuilt rule asset schema', () => { tags: [0, 1, 2], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "0" supplied to "tags"', - 'Invalid value "1" supplied to "tags"', - 'Invalid value "2" supplied to "tags"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"tags.0: Expected string, received number, tags.1: Expected string, received number, tags.2: Expected string, received number"` + ); }); test('You cannot send in an array of threat that are missing "framework"', () => { @@ -670,13 +318,9 @@ describe('Prebuilt rule asset schema', () => { ], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "threat,framework"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"threat.0.framework: Required"`); }); test('You cannot send in an array of threat that are missing "tactic"', () => { @@ -698,13 +342,9 @@ describe('Prebuilt rule asset schema', () => { ], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "threat,tactic"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"threat.0.tactic: Required"`); }); test('You can send in an array of threat that are missing "technique"', () => { @@ -724,10 +364,9 @@ describe('Prebuilt rule asset schema', () => { ], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can optionally send in an array of false positives', () => { @@ -736,10 +375,9 @@ describe('Prebuilt rule asset schema', () => { false_positives: ['false_1', 'false_2'], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot send in an array of false positives that are numbers', () => { @@ -750,28 +388,24 @@ describe('Prebuilt rule asset schema', () => { false_positives: [5, 4], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "5" supplied to "false_positives"', - 'Invalid value "4" supplied to "false_positives"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"false_positives.0: Expected string, received number, false_positives.1: Expected string, received number"` + ); }); + test('You cannot set the risk_score to 101', () => { const payload: PrebuiltRuleAsset = { ...getPrebuiltRuleMock(), risk_score: 101, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "101" supplied to "risk_score"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"risk_score: Number must be less than or equal to 100"` + ); }); test('You cannot set the risk_score to -1', () => { @@ -780,11 +414,11 @@ describe('Prebuilt rule asset schema', () => { risk_score: -1, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "-1" supplied to "risk_score"']); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"risk_score: Number must be greater than or equal to 0"` + ); }); test('You can set the risk_score to 0', () => { @@ -793,10 +427,9 @@ describe('Prebuilt rule asset schema', () => { risk_score: 0, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set the risk_score to 100', () => { @@ -805,10 +438,9 @@ describe('Prebuilt rule asset schema', () => { risk_score: 100, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set meta to any object you want', () => { @@ -819,10 +451,9 @@ describe('Prebuilt rule asset schema', () => { }, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot create meta as a string', () => { @@ -831,13 +462,11 @@ describe('Prebuilt rule asset schema', () => { meta: 'should not work', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "should not work" supplied to "meta"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"meta: Expected object, received string"` + ); }); test('validates with timeline_id and timeline_title', () => { @@ -847,10 +476,9 @@ describe('Prebuilt rule asset schema', () => { timeline_title: 'timeline-title', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot set the severity to a value other than low, medium, high, or critical', () => { @@ -859,11 +487,11 @@ describe('Prebuilt rule asset schema', () => { severity: 'junk', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual(['Invalid value "junk" supplied to "severity"']); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"severity: Invalid enum value. Expected 'low' | 'medium' | 'high' | 'critical', received 'junk'"` + ); }); test('You cannot send in an array of actions that are missing "group"', () => { @@ -872,13 +500,9 @@ describe('Prebuilt rule asset schema', () => { actions: [{ id: 'id', action_type_id: 'action_type_id', params: {} }], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,group"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"actions.0.group: Required"`); }); test('You cannot send in an array of actions that are missing "id"', () => { @@ -887,13 +511,9 @@ describe('Prebuilt rule asset schema', () => { actions: [{ group: 'group', action_type_id: 'action_type_id', params: {} }], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,id"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"actions.0.id: Required"`); }); test('You cannot send in an array of actions that are missing "action_type_id"', () => { @@ -901,14 +521,11 @@ describe('Prebuilt rule asset schema', () => { ...getPrebuiltRuleMock(), actions: [{ group: 'group', id: 'id', params: {} }], }; - - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,action_type_id"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"actions.0.action_type_id: Required"` + ); }); test('You cannot send in an array of actions that are missing "params"', () => { @@ -917,13 +534,9 @@ describe('Prebuilt rule asset schema', () => { actions: [{ group: 'group', id: 'id', action_type_id: 'action_type_id' }], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,params"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot(`"actions.0.params: Required"`); }); test('You cannot send in an array of actions that are including "actionTypeId"', () => { @@ -939,13 +552,11 @@ describe('Prebuilt rule asset schema', () => { ], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "actions,action_type_id"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"actions.0.action_type_id: Required"` + ); }); describe('note', () => { @@ -955,10 +566,9 @@ describe('Prebuilt rule asset schema', () => { note: '# documentation markdown here', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You can set note to an empty string', () => { @@ -967,10 +577,9 @@ describe('Prebuilt rule asset schema', () => { note: '', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('You cannot create note as an object', () => { @@ -981,13 +590,11 @@ describe('Prebuilt rule asset schema', () => { }, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "{"somethingHere":"something else"}" supplied to "note"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"note: Expected string, received object"` + ); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note] does validate', () => { @@ -1006,10 +613,9 @@ describe('Prebuilt rule asset schema', () => { version: 1, }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); }); @@ -1032,10 +638,9 @@ describe('Prebuilt rule asset schema', () => { exceptions_list: getListArrayMock(), }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filter, risk_score, note, version, and empty exceptions_list] does validate', () => { @@ -1056,10 +661,9 @@ describe('Prebuilt rule asset schema', () => { exceptions_list: [], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); test('rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, version, and invalid exceptions_list] does NOT validate', () => { @@ -1080,15 +684,11 @@ describe('Prebuilt rule asset schema', () => { exceptions_list: [{ id: 'uuid_here', namespace_type: 'not a namespace type' }], }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([ - 'Invalid value "undefined" supplied to "exceptions_list,list_id"', - 'Invalid value "undefined" supplied to "exceptions_list,type"', - 'Invalid value "not a namespace type" supplied to "exceptions_list,namespace_type"', - ]); - expect(message.schema).toEqual({}); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseError(result); + expect(stringifyZodError(result.error)).toMatchInlineSnapshot( + `"exceptions_list.0.list_id: Required, exceptions_list.0.type: Required, exceptions_list.0.namespace_type: Invalid enum value. Expected 'agnostic' | 'single', received 'not a namespace type'"` + ); }); test('[rule_id, description, from, to, index, name, severity, interval, type, filters, risk_score, note, version, and non-existent exceptions_list] does validate with empty exceptions_list', () => { @@ -1108,20 +708,18 @@ describe('Prebuilt rule asset schema', () => { note: '# some markdown', }; - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); }); describe('threat_mapping', () => { test('You can set a threat query, index, mapping, filters on a pre-packaged rule', () => { const payload = getPrebuiltThreatMatchRuleMock(); - const decoded = PrebuiltRuleAsset.decode(payload); - const checked = exactCheck(payload, decoded); - const message = pipe(checked, foldLeftRight); - expect(getPaths(left(message.errors))).toEqual([]); + const result = PrebuiltRuleAsset.safeParse(payload); + expectParseSuccess(result); + expect(result.data).toEqual(payload); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts index 40666a39af4b93..07fb5640eb482a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/prebuilt_rules/model/rule_assets/prebuilt_rule_asset.ts @@ -5,7 +5,7 @@ * 2.0. */ -import * as t from 'io-ts'; +import * as z from 'zod'; import { RelatedIntegrationArray, RequiredFieldArray, @@ -30,22 +30,13 @@ import { * - rule_id is required here * - version is a required field that must exist */ -export type PrebuiltRuleAsset = t.TypeOf; -export const PrebuiltRuleAsset = t.intersection([ - BaseCreateProps, - TypeSpecificCreateProps, - // version is required here, which supercedes the defaultable version in baseSchema - t.exact( - t.type({ - rule_id: RuleSignatureId, - version: RuleVersion, - }) - ), - t.exact( - t.partial({ - related_integrations: RelatedIntegrationArray, - required_fields: RequiredFieldArray, - setup: SetupGuide, - }) - ), -]); +export type PrebuiltRuleAsset = z.infer; +export const PrebuiltRuleAsset = BaseCreateProps.and(TypeSpecificCreateProps).and( + z.object({ + rule_id: RuleSignatureId, + version: RuleVersion, + related_integrations: RelatedIntegrationArray.optional(), + required_fields: RequiredFieldArray.optional(), + setup: SetupGuide.optional(), + }) +); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts index eeef7846b519a3..59e875a2616777 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.test.ts @@ -199,7 +199,9 @@ describe('Bulk create rules route', () => { ], }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('Failed to parse "from" on rule param'); + expect(result.badRequest).toHaveBeenCalledWith( + '0.from: Failed to parse date-math expression' + ); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts index ecbf6e47f1825f..7ab03f2ac7dcd4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_create_rules/route.ts @@ -6,8 +6,8 @@ */ import type { IKibanaResponse, Logger } from '@kbn/core/server'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; import { DETECTION_ENGINE_RULES_BULK_CREATE } from '../../../../../../../common/constants'; import { BulkCreateRulesRequestBody, @@ -23,7 +23,7 @@ import { createRules } from '../../../logic/crud/create_rules'; import { readRules } from '../../../logic/crud/read_rules'; import { getDuplicates } from './get_duplicates'; import { transformValidateBulkError } from '../../../utils/validate'; -import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { validateRuleDefaultExceptionList } from '../../../logic/exceptions/validate_rule_default_exception_list'; import { validateRulesWithDuplicatedDefaultExceptionsList } from '../../../logic/exceptions/validate_rules_with_duplicated_default_exceptions_list'; @@ -55,7 +55,7 @@ export const bulkCreateRulesRoute = ( version: '2023-10-31', validate: { request: { - body: buildRouteValidation(BulkCreateRulesRequestBody), + body: buildRouteValidationWithZod(BulkCreateRulesRequestBody), }, }, }, @@ -64,100 +64,100 @@ export const bulkCreateRulesRoute = ( const siemResponse = buildSiemResponse(response); - const ctx = await context.resolve(['core', 'securitySolution', 'licensing', 'alerting']); - - const rulesClient = ctx.alerting.getRulesClient(); - const savedObjectsClient = ctx.core.savedObjects.client; - - const mlAuthz = buildMlAuthz({ - license: ctx.licensing.license, - ml, - request, - savedObjectsClient, - }); - - const ruleDefinitions = request.body; - const dupes = getDuplicates(ruleDefinitions, 'rule_id'); - - const rules = await Promise.all( - ruleDefinitions - .filter((rule) => rule.rule_id == null || !dupes.includes(rule.rule_id)) - .map(async (payloadRule) => { - if (payloadRule.rule_id != null) { - const rule = await readRules({ - id: undefined, - rulesClient, - ruleId: payloadRule.rule_id, - }); - if (rule != null) { - return createBulkErrorObject({ + try { + const ctx = await context.resolve(['core', 'securitySolution', 'licensing', 'alerting']); + + const rulesClient = ctx.alerting.getRulesClient(); + const savedObjectsClient = ctx.core.savedObjects.client; + + const mlAuthz = buildMlAuthz({ + license: ctx.licensing.license, + ml, + request, + savedObjectsClient, + }); + + const ruleDefinitions = request.body; + const dupes = getDuplicates(ruleDefinitions, 'rule_id'); + + const rules = await Promise.all( + ruleDefinitions + .filter((rule) => rule.rule_id == null || !dupes.includes(rule.rule_id)) + .map(async (payloadRule) => { + if (payloadRule.rule_id != null) { + const rule = await readRules({ + id: undefined, + rulesClient, ruleId: payloadRule.rule_id, - statusCode: 409, - message: `rule_id: "${payloadRule.rule_id}" already exists`, }); + if (rule != null) { + return createBulkErrorObject({ + ruleId: payloadRule.rule_id, + statusCode: 409, + message: `rule_id: "${payloadRule.rule_id}" already exists`, + }); + } } - } - - try { - validateRulesWithDuplicatedDefaultExceptionsList({ - allRules: request.body, - exceptionsList: payloadRule.exceptions_list, - ruleId: payloadRule.rule_id, - }); - - await validateRuleDefaultExceptionList({ - exceptionsList: payloadRule.exceptions_list, - rulesClient, - ruleRuleId: payloadRule.rule_id, - ruleId: undefined, - }); - - const validationErrors = validateCreateRuleProps(payloadRule); - if (validationErrors.length) { - return createBulkErrorObject({ + + try { + validateRulesWithDuplicatedDefaultExceptionsList({ + allRules: request.body, + exceptionsList: payloadRule.exceptions_list, ruleId: payloadRule.rule_id, - statusCode: 400, - message: validationErrors.join(), }); - } - throwAuthzError(await mlAuthz.validateRuleType(payloadRule.type)); - - const createdRule = await createRules({ - rulesClient, - params: payloadRule, - }); - - return transformValidateBulkError(createdRule.params.ruleId, createdRule); - } catch (err) { - return transformBulkError( - payloadRule.rule_id, - err as Error & { statusCode?: number } - ); - } - }) - ); - const rulesBulk = [ - ...rules, - ...dupes.map((ruleId) => - createBulkErrorObject({ - ruleId, - statusCode: 409, - message: `rule_id: "${ruleId}" already exists`, - }) - ), - ]; - const [validated, errors] = validate(rulesBulk, BulkCrudRulesResponse); - if (errors != null) { - return siemResponse.error({ - statusCode: 500, - body: errors, + await validateRuleDefaultExceptionList({ + exceptionsList: payloadRule.exceptions_list, + rulesClient, + ruleRuleId: payloadRule.rule_id, + ruleId: undefined, + }); + + const validationErrors = validateCreateRuleProps(payloadRule); + if (validationErrors.length) { + return createBulkErrorObject({ + ruleId: payloadRule.rule_id, + statusCode: 400, + message: validationErrors.join(), + }); + } + + throwAuthzError(await mlAuthz.validateRuleType(payloadRule.type)); + + const createdRule = await createRules({ + rulesClient, + params: payloadRule, + }); + + return transformValidateBulkError(createdRule.params.ruleId, createdRule); + } catch (err) { + return transformBulkError( + payloadRule.rule_id, + err as Error & { statusCode?: number } + ); + } + }) + ); + const rulesBulk = [ + ...rules, + ...dupes.map((ruleId) => + createBulkErrorObject({ + ruleId, + statusCode: 409, + message: `rule_id: "${ruleId}" already exists`, + }) + ), + ]; + return response.ok({ + body: BulkCrudRulesResponse.parse(rulesBulk), headers: getDeprecatedBulkEndpointHeader(DETECTION_ENGINE_RULES_BULK_CREATE), }); - } else { - return response.ok({ - body: validated ?? {}, + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, headers: getDeprecatedBulkEndpointHeader(DETECTION_ENGINE_RULES_BULK_CREATE), + statusCode: error.statusCode, }); } } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts index fb6be3e5e25eaa..639f2792158013 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_delete_rules/route.ts @@ -7,7 +7,7 @@ import type { VersionedRouteConfig } from '@kbn/core-http-server'; import type { IKibanaResponse, Logger, RequestHandler } from '@kbn/core/server'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; import { BulkCrudRulesResponse, BulkDeleteRulesRequestBody, @@ -18,7 +18,7 @@ import type { SecuritySolutionPluginRouter, SecuritySolutionRequestHandlerContext, } from '../../../../../../types'; -import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse, createBulkErrorObject, @@ -51,51 +51,52 @@ export const bulkDeleteRulesRoute = (router: SecuritySolutionPluginRouter, logge const siemResponse = buildSiemResponse(response); - const ctx = await context.resolve(['core', 'securitySolution', 'alerting']); + try { + const ctx = await context.resolve(['core', 'securitySolution', 'alerting']); - const rulesClient = ctx.alerting.getRulesClient(); + const rulesClient = ctx.alerting.getRulesClient(); - const rules = await Promise.all( - request.body.map(async (payloadRule) => { - const { id, rule_id: ruleId } = payloadRule; - const idOrRuleIdOrUnknown = id ?? ruleId ?? '(unknown id)'; - const validationErrors = validateQueryRuleByIds(payloadRule); - if (validationErrors.length) { - return createBulkErrorObject({ - ruleId: idOrRuleIdOrUnknown, - statusCode: 400, - message: validationErrors.join(), - }); - } - - try { - const rule = await readRules({ rulesClient, id, ruleId }); - if (!rule) { - return getIdBulkError({ id, ruleId }); + const rules = await Promise.all( + request.body.map(async (payloadRule) => { + const { id, rule_id: ruleId } = payloadRule; + const idOrRuleIdOrUnknown = id ?? ruleId ?? '(unknown id)'; + const validationErrors = validateQueryRuleByIds(payloadRule); + if (validationErrors.length) { + return createBulkErrorObject({ + ruleId: idOrRuleIdOrUnknown, + statusCode: 400, + message: validationErrors.join(), + }); } - await deleteRules({ - ruleId: rule.id, - rulesClient, - }); + try { + const rule = await readRules({ rulesClient, id, ruleId }); + if (!rule) { + return getIdBulkError({ id, ruleId }); + } - return transformValidateBulkError(idOrRuleIdOrUnknown, rule); - } catch (err) { - return transformBulkError(idOrRuleIdOrUnknown, err); - } - }) - ); - const [validated, errors] = validate(rules, BulkCrudRulesResponse); - if (errors != null) { - return siemResponse.error({ - statusCode: 500, - body: errors, + await deleteRules({ + ruleId: rule.id, + rulesClient, + }); + + return transformValidateBulkError(idOrRuleIdOrUnknown, rule); + } catch (err) { + return transformBulkError(idOrRuleIdOrUnknown, err); + } + }) + ); + + return response.ok({ + body: BulkCrudRulesResponse.parse(rules), headers: getDeprecatedBulkEndpointHeader(DETECTION_ENGINE_RULES_BULK_DELETE), }); - } else { - return response.ok({ - body: validated ?? {}, + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, headers: getDeprecatedBulkEndpointHeader(DETECTION_ENGINE_RULES_BULK_DELETE), + statusCode: error.statusCode, }); } }; @@ -111,7 +112,7 @@ export const bulkDeleteRulesRoute = (router: SecuritySolutionPluginRouter, logge version: '2023-10-31', validate: { request: { - body: buildRouteValidation(BulkDeleteRulesRequestBody), + body: buildRouteValidationWithZod(BulkDeleteRulesRequestBody), }, }, }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts index 4fdc0d0dedda21..fc3d87d32b4325 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.test.ts @@ -191,9 +191,7 @@ describe('Bulk patch rules route', () => { }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "unknown_type" supplied to "type",Invalid value "kuery" supplied to "language"' - ); + expect(result.badRequest).toHaveBeenCalledWith('0: Invalid input'); }); test('allows rule type of query and custom from and interval', async () => { @@ -220,7 +218,9 @@ describe('Bulk patch rules route', () => { ], }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('Failed to parse "from" on rule param'); + expect(result.badRequest).toHaveBeenCalledWith( + '0.from: Failed to parse date-math expression' + ); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts index f29c84cf71049e..7d7c4a44fa1e10 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_patch_rules/route.ts @@ -5,16 +5,16 @@ * 2.0. */ -import { validate } from '@kbn/securitysolution-io-ts-utils'; import type { IKibanaResponse, Logger } from '@kbn/core/server'; +import { transformError } from '@kbn/securitysolution-es-utils'; import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../../../common/constants'; import { BulkPatchRulesRequestBody, BulkCrudRulesResponse, } from '../../../../../../../common/api/detection_engine/rule_management'; -import { buildRouteValidationNonExact } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import type { SetupPlugins } from '../../../../../../plugin'; import { buildMlAuthz } from '../../../../../machine_learning/authz'; @@ -49,7 +49,7 @@ export const bulkPatchRulesRoute = ( version: '2023-10-31', validate: { request: { - body: buildRouteValidationNonExact(BulkPatchRulesRequestBody), + body: buildRouteValidationWithZod(BulkPatchRulesRequestBody), }, }, }, @@ -58,78 +58,78 @@ export const bulkPatchRulesRoute = ( const siemResponse = buildSiemResponse(response); - const ctx = await context.resolve(['core', 'securitySolution', 'alerting', 'licensing']); + try { + const ctx = await context.resolve(['core', 'securitySolution', 'alerting', 'licensing']); - const rulesClient = ctx.alerting.getRulesClient(); - const savedObjectsClient = ctx.core.savedObjects.client; + const rulesClient = ctx.alerting.getRulesClient(); + const savedObjectsClient = ctx.core.savedObjects.client; - const mlAuthz = buildMlAuthz({ - license: ctx.licensing.license, - ml, - request, - savedObjectsClient, - }); + const mlAuthz = buildMlAuthz({ + license: ctx.licensing.license, + ml, + request, + savedObjectsClient, + }); - const rules = await Promise.all( - request.body.map(async (payloadRule) => { - const idOrRuleIdOrUnknown = payloadRule.id ?? payloadRule.rule_id ?? '(unknown id)'; + const rules = await Promise.all( + request.body.map(async (payloadRule) => { + const idOrRuleIdOrUnknown = payloadRule.id ?? payloadRule.rule_id ?? '(unknown id)'; - try { - if (payloadRule.type) { - // reject an unauthorized "promotion" to ML - throwAuthzError(await mlAuthz.validateRuleType(payloadRule.type)); - } + try { + if (payloadRule.type) { + // reject an unauthorized "promotion" to ML + throwAuthzError(await mlAuthz.validateRuleType(payloadRule.type)); + } - const existingRule = await readRules({ - rulesClient, - ruleId: payloadRule.rule_id, - id: payloadRule.id, - }); - if (existingRule?.params.type) { - // reject an unauthorized modification of an ML rule - throwAuthzError(await mlAuthz.validateRuleType(existingRule?.params.type)); - } + const existingRule = await readRules({ + rulesClient, + ruleId: payloadRule.rule_id, + id: payloadRule.id, + }); + if (existingRule?.params.type) { + // reject an unauthorized modification of an ML rule + throwAuthzError(await mlAuthz.validateRuleType(existingRule?.params.type)); + } - validateRulesWithDuplicatedDefaultExceptionsList({ - allRules: request.body, - exceptionsList: payloadRule.exceptions_list, - ruleId: idOrRuleIdOrUnknown, - }); + validateRulesWithDuplicatedDefaultExceptionsList({ + allRules: request.body, + exceptionsList: payloadRule.exceptions_list, + ruleId: idOrRuleIdOrUnknown, + }); - await validateRuleDefaultExceptionList({ - exceptionsList: payloadRule.exceptions_list, - rulesClient, - ruleRuleId: payloadRule.rule_id, - ruleId: payloadRule.id, - }); + await validateRuleDefaultExceptionList({ + exceptionsList: payloadRule.exceptions_list, + rulesClient, + ruleRuleId: payloadRule.rule_id, + ruleId: payloadRule.id, + }); - const rule = await patchRules({ - existingRule, - rulesClient, - nextParams: payloadRule, - }); - if (rule != null && rule.enabled != null && rule.name != null) { - return transformValidateBulkError(rule.id, rule); - } else { - return getIdBulkError({ id: payloadRule.id, ruleId: payloadRule.rule_id }); + const rule = await patchRules({ + existingRule, + rulesClient, + nextParams: payloadRule, + }); + if (rule != null && rule.enabled != null && rule.name != null) { + return transformValidateBulkError(rule.id, rule); + } else { + return getIdBulkError({ id: payloadRule.id, ruleId: payloadRule.rule_id }); + } + } catch (err) { + return transformBulkError(idOrRuleIdOrUnknown, err); } - } catch (err) { - return transformBulkError(idOrRuleIdOrUnknown, err); - } - }) - ); + }) + ); - const [validated, errors] = validate(rules, BulkCrudRulesResponse); - if (errors != null) { - return siemResponse.error({ - statusCode: 500, - body: errors, + return response.ok({ + body: BulkCrudRulesResponse.parse(rules), headers: getDeprecatedBulkEndpointHeader(DETECTION_ENGINE_RULES_BULK_UPDATE), }); - } else { - return response.ok({ - body: validated ?? {}, + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, headers: getDeprecatedBulkEndpointHeader(DETECTION_ENGINE_RULES_BULK_UPDATE), + statusCode: error.statusCode, }); } } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.test.ts index ba9a61d2126e46..98752160fab96d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.test.ts @@ -178,7 +178,9 @@ describe('Bulk update rules route', () => { ], }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('Failed to parse "from" on rule param'); + expect(result.badRequest).toHaveBeenCalledWith( + '0.from: Failed to parse date-math expression' + ); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts index 13d9f0945f0340..dd9fec81f34a6e 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/bulk_update_rules/route.ts @@ -6,15 +6,15 @@ */ import type { IKibanaResponse, Logger } from '@kbn/core/server'; -import { validate } from '@kbn/securitysolution-io-ts-utils'; +import { transformError } from '@kbn/securitysolution-es-utils'; import { BulkUpdateRulesRequestBody, validateUpdateRuleProps, BulkCrudRulesResponse, } from '../../../../../../../common/api/detection_engine/rule_management'; -import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; import { DETECTION_ENGINE_RULES_BULK_UPDATE } from '../../../../../../../common/constants'; import type { SetupPlugins } from '../../../../../../plugin'; @@ -54,7 +54,7 @@ export const bulkUpdateRulesRoute = ( version: '2023-10-31', validate: { request: { - body: buildRouteValidation(BulkUpdateRulesRequestBody), + body: buildRouteValidationWithZod(BulkUpdateRulesRequestBody), }, }, }, @@ -63,78 +63,78 @@ export const bulkUpdateRulesRoute = ( const siemResponse = buildSiemResponse(response); - const ctx = await context.resolve(['core', 'securitySolution', 'alerting', 'licensing']); + try { + const ctx = await context.resolve(['core', 'securitySolution', 'alerting', 'licensing']); - const rulesClient = ctx.alerting.getRulesClient(); - const savedObjectsClient = ctx.core.savedObjects.client; + const rulesClient = ctx.alerting.getRulesClient(); + const savedObjectsClient = ctx.core.savedObjects.client; - const mlAuthz = buildMlAuthz({ - license: ctx.licensing.license, - ml, - request, - savedObjectsClient, - }); + const mlAuthz = buildMlAuthz({ + license: ctx.licensing.license, + ml, + request, + savedObjectsClient, + }); - const rules = await Promise.all( - request.body.map(async (payloadRule) => { - const idOrRuleIdOrUnknown = payloadRule.id ?? payloadRule.rule_id ?? '(unknown id)'; - try { - const validationErrors = validateUpdateRuleProps(payloadRule); - if (validationErrors.length) { - return createBulkErrorObject({ - ruleId: payloadRule.rule_id, - statusCode: 400, - message: validationErrors.join(), - }); - } + const rules = await Promise.all( + request.body.map(async (payloadRule) => { + const idOrRuleIdOrUnknown = payloadRule.id ?? payloadRule.rule_id ?? '(unknown id)'; + try { + const validationErrors = validateUpdateRuleProps(payloadRule); + if (validationErrors.length) { + return createBulkErrorObject({ + ruleId: payloadRule.rule_id, + statusCode: 400, + message: validationErrors.join(), + }); + } - throwAuthzError(await mlAuthz.validateRuleType(payloadRule.type)); + throwAuthzError(await mlAuthz.validateRuleType(payloadRule.type)); - const existingRule = await readRules({ - rulesClient, - ruleId: payloadRule.rule_id, - id: payloadRule.id, - }); + const existingRule = await readRules({ + rulesClient, + ruleId: payloadRule.rule_id, + id: payloadRule.id, + }); - validateRulesWithDuplicatedDefaultExceptionsList({ - allRules: request.body, - exceptionsList: payloadRule.exceptions_list, - ruleId: idOrRuleIdOrUnknown, - }); - await validateRuleDefaultExceptionList({ - exceptionsList: payloadRule.exceptions_list, - rulesClient, - ruleRuleId: payloadRule.rule_id, - ruleId: payloadRule.id, - }); + validateRulesWithDuplicatedDefaultExceptionsList({ + allRules: request.body, + exceptionsList: payloadRule.exceptions_list, + ruleId: idOrRuleIdOrUnknown, + }); + await validateRuleDefaultExceptionList({ + exceptionsList: payloadRule.exceptions_list, + rulesClient, + ruleRuleId: payloadRule.rule_id, + ruleId: payloadRule.id, + }); - const rule = await updateRules({ - rulesClient, - existingRule, - ruleUpdate: payloadRule, - }); - if (rule != null) { - return transformValidateBulkError(rule.id, rule); - } else { - return getIdBulkError({ id: payloadRule.id, ruleId: payloadRule.rule_id }); + const rule = await updateRules({ + rulesClient, + existingRule, + ruleUpdate: payloadRule, + }); + if (rule != null) { + return transformValidateBulkError(rule.id, rule); + } else { + return getIdBulkError({ id: payloadRule.id, ruleId: payloadRule.rule_id }); + } + } catch (err) { + return transformBulkError(idOrRuleIdOrUnknown, err); } - } catch (err) { - return transformBulkError(idOrRuleIdOrUnknown, err); - } - }) - ); + }) + ); - const [validated, errors] = validate(rules, BulkCrudRulesResponse); - if (errors != null) { - return siemResponse.error({ - statusCode: 500, - body: errors, + return response.ok({ + body: BulkCrudRulesResponse.parse(rules), headers: getDeprecatedBulkEndpointHeader(DETECTION_ENGINE_RULES_BULK_UPDATE), }); - } else { - return response.ok({ - body: validated ?? {}, + } catch (err) { + const error = transformError(err); + return siemResponse.error({ + body: error.message, headers: getDeprecatedBulkEndpointHeader(DETECTION_ENGINE_RULES_BULK_UPDATE), + statusCode: error.statusCode, }); } } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts index 18efcc5c94c2e3..5fed0b4e3446a1 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.test.ts @@ -173,7 +173,7 @@ describe('Create rule route', () => { }, }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('Failed to parse "from" on rule param'); + expect(result.badRequest).toHaveBeenCalledWith('from: Failed to parse date-math expression'); }); }); describe('rule containing response actions', () => { @@ -236,9 +236,7 @@ describe('Create rule route', () => { }, }); const result = await server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "processes" supplied to "response_actions,params,command"' - ); + expect(result.badRequest).toHaveBeenCalledWith('Invalid input'); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts index 746917a30c2987..e9c84c1c50f5cb 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/create_rule/route.ts @@ -15,7 +15,7 @@ import { import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SetupPlugins } from '../../../../../../plugin'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildMlAuthz } from '../../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../../machine_learning/validation'; import { buildSiemResponse } from '../../../../routes/utils'; @@ -43,7 +43,7 @@ export const createRuleRoute = ( version: '2023-10-31', validate: { request: { - body: buildRouteValidation(CreateRuleRequestBody), + body: buildRouteValidationWithZod(CreateRuleRequestBody), }, }, }, @@ -109,12 +109,9 @@ export const createRuleRoute = ( params: request.body, }); - const [validated, errors] = transformValidate(createdRule); - if (errors != null) { - return siemResponse.error({ statusCode: 500, body: errors }); - } else { - return response.ok({ body: validated }); - } + return response.ok({ + body: transformValidate(createdRule), + }); } catch (err) { const error = transformError(err as Error); return siemResponse.error({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts index c1479b9ef125d7..f45901082d393a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/delete_rule/route.ts @@ -14,7 +14,7 @@ import { } from '../../../../../../../common/api/detection_engine/rule_management'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../routes/utils'; import { deleteRules } from '../../../logic/crud/delete_rules'; import { readRules } from '../../../logic/crud/read_rules'; @@ -34,7 +34,7 @@ export const deleteRuleRoute = (router: SecuritySolutionPluginRouter) => { version: '2023-10-31', validate: { request: { - query: buildRouteValidation(DeleteRuleRequestQuery), + query: buildRouteValidationWithZod(DeleteRuleRequestQuery), }, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts index e50fd79f8cf8a4..677556f3142396 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.test.ts @@ -199,9 +199,7 @@ describe('Patch rule route', () => { }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "unknown_type" supplied to "type",Invalid value "kuery" supplied to "language"' - ); + expect(result.badRequest).toHaveBeenCalledWith('Invalid input'); }); test('allows rule type of query and custom from and interval', async () => { @@ -226,7 +224,7 @@ describe('Patch rule route', () => { }, }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('Failed to parse "from" on rule param'); + expect(result.badRequest).toHaveBeenCalledWith('from: Failed to parse date-math expression'); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts index 39fdd303063788..5401e2361ca585 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/patch_rule/route.ts @@ -15,7 +15,7 @@ import { import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SetupPlugins } from '../../../../../../plugin'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidationNonExact } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildMlAuthz } from '../../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../../machine_learning/validation'; import { buildSiemResponse } from '../../../../routes/utils'; @@ -43,7 +43,7 @@ export const patchRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupPl // Use non-exact validation because everything is optional in patch - since everything is optional, // io-ts can't find the right schema from the type specific union and the exact check breaks. // We do type specific validation after fetching the existing rule so we know the rule type. - body: buildRouteValidationNonExact(PatchRuleRequestBody), + body: buildRouteValidationWithZod(PatchRuleRequestBody), }, }, }, @@ -93,12 +93,9 @@ export const patchRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupPl nextParams: params, }); if (rule != null && rule.enabled != null && rule.name != null) { - const [validated, errors] = transformValidate(rule); - if (errors != null) { - return siemResponse.error({ statusCode: 500, body: errors }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ + body: transformValidate(rule), + }); } else { const error = getIdError({ id: params.id, ruleId: params.rule_id }); return siemResponse.error({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts index 2bd0cc76e18509..ade1f280c046d0 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/read_rule/route.ts @@ -14,7 +14,7 @@ import { } from '../../../../../../../common/api/detection_engine/rule_management'; import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildSiemResponse } from '../../../../routes/utils'; import { readRules } from '../../../logic/crud/read_rules'; import { getIdError, transform } from '../../../utils/utils'; @@ -33,7 +33,7 @@ export const readRuleRoute = (router: SecuritySolutionPluginRouter, logger: Logg version: '2023-10-31', validate: { request: { - query: buildRouteValidation(ReadRuleRequestQuery), + query: buildRouteValidationWithZod(ReadRuleRequestQuery), }, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts index 6266764018974d..e580f5cc116623 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.test.ts @@ -181,7 +181,7 @@ describe('Update rule route', () => { }, }); const result = server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith('Failed to parse "from" on rule param'); + expect(result.badRequest).toHaveBeenCalledWith('from: Failed to parse date-math expression'); }); }); describe('rule containing response actions', () => { @@ -283,9 +283,7 @@ describe('Update rule route', () => { }, }); const result = await server.validate(request); - expect(result.badRequest).toHaveBeenCalledWith( - 'Invalid value "processes" supplied to "response_actions,params,command"' - ); + expect(result.badRequest).toHaveBeenCalledWith('Invalid input'); }); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts index a281acba9857b1..215a0827b015fd 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/api/rules/update_rule/route.ts @@ -15,7 +15,7 @@ import { import { DETECTION_ENGINE_RULES_URL } from '../../../../../../../common/constants'; import type { SetupPlugins } from '../../../../../../plugin'; import type { SecuritySolutionPluginRouter } from '../../../../../../types'; -import { buildRouteValidation } from '../../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../../utils/build_validation/route_validation'; import { buildMlAuthz } from '../../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../../machine_learning/validation'; import { buildSiemResponse } from '../../../../routes/utils'; @@ -40,7 +40,7 @@ export const updateRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupP version: '2023-10-31', validate: { request: { - body: buildRouteValidation(UpdateRuleRequestBody), + body: buildRouteValidationWithZod(UpdateRuleRequestBody), }, }, }, @@ -92,12 +92,9 @@ export const updateRuleRoute = (router: SecuritySolutionPluginRouter, ml: SetupP }); if (rule != null) { - const [validated, errors] = transformValidate(rule); - if (errors != null) { - return siemResponse.error({ statusCode: 500, body: errors }); - } else { - return response.ok({ body: validated ?? {} }); - } + return response.ok({ + body: transformValidate(rule), + }); } else { const error = getIdError({ id: request.body.id, ruleId: request.body.rule_id }); return siemResponse.error({ diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.ts index e01bcd4b7e2ec4..d699d5ee7dd559 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/read_rules.ts @@ -14,7 +14,7 @@ import type { } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { withSecuritySpan } from '../../../../../utils/with_security_span'; import type { RuleParams } from '../../../rule_schema'; -import { isAlertType } from '../../../rule_schema'; +import { hasValidRuleType } from '../../../rule_schema'; import { findRules } from '../search/find_rules'; export interface ReadRuleOptions { @@ -42,7 +42,7 @@ export const readRules = async ({ if (id != null) { try { const rule = await rulesClient.resolve({ id }); - if (isAlertType(rule)) { + if (hasValidRuleType(rule)) { if (rule?.outcome === 'exactMatch') { const { outcome, ...restOfRule } = rule; return restOfRule; @@ -69,7 +69,7 @@ export const readRules = async ({ sortField: undefined, sortOrder: undefined, }); - if (ruleFromFind.data.length === 0 || !isAlertType(ruleFromFind.data[0])) { + if (ruleFromFind.data.length === 0 || !hasValidRuleType(ruleFromFind.data[0])) { return null; } else { return ruleFromFind.data[0]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.ts index aa9d7c4f8303b0..cfbf6a639bb5ed 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/crud/update_rules.ts @@ -30,7 +30,8 @@ export const updateRules = async ({ return null; } - const alertActions = ruleUpdate.actions?.map(transformRuleToAlertAction) ?? []; + const alertActions = + ruleUpdate.actions?.map((action) => transformRuleToAlertAction(action)) ?? []; const actions = transformToActionFrequency(alertActions, ruleUpdate.throttle); const typeSpecificParams = typeSpecificSnakeToCamel(ruleUpdate); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts index 90feafaf036fa3..c92b37d7710dbe 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/logic/export/get_export_by_object_ids.ts @@ -16,7 +16,7 @@ import type { RulesClient, RuleExecutorServices } from '@kbn/alerting-plugin/ser import type { ActionsClient } from '@kbn/actions-plugin/server'; import { getExportDetailsNdjson } from './get_export_details_ndjson'; -import { isAlertType } from '../../../rule_schema'; +import { hasValidRuleType } from '../../../rule_schema'; import { findRules } from '../search/find_rules'; import { transformRuleToExportableFormat } from '../../utils/utils'; import { getRuleExceptionsForExport } from './get_export_rule_exceptions'; @@ -126,7 +126,7 @@ export const getRulesFromObjects = async ( const matchingRule = rules.data.find((rule) => rule.params.ruleId === ruleId); if ( matchingRule != null && - isAlertType(matchingRule) && + hasValidRuleType(matchingRule) && matchingRule.params.immutable !== true ) { return { diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.test.ts index 02ab6646020437..d03fe3587ce3b4 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.test.ts @@ -15,6 +15,7 @@ import { getThreatRuleParams, getThresholdRuleParams, } from '../../rule_schema/mocks'; +import type { PatchRuleRequestBody } from '../../../../../common/api/detection_engine'; describe('rule_converters', () => { describe('patchTypeSpecificSnakeToCamel', () => { @@ -40,10 +41,10 @@ describe('rule_converters', () => { timestamp_field: 1, event_category_override: 1, tiebreaker_field: 1, - }; + } as PatchRuleRequestBody; const rule = getEqlRuleParams(); expect(() => patchTypeSpecificSnakeToCamel(patchParams, rule)).toThrowError( - 'Invalid value "1" supplied to "timestamp_field",Invalid value "1" supplied to "event_category_override",Invalid value "1" supplied to "tiebreaker_field"' + 'event_category_override: Expected string, received number, tiebreaker_field: Expected string, received number, timestamp_field: Expected string, received number' ); }); @@ -66,10 +67,10 @@ describe('rule_converters', () => { const patchParams = { threat_indicator_path: 1, threat_query: 1, - }; + } as PatchRuleRequestBody; const rule = getThreatRuleParams(); expect(() => patchTypeSpecificSnakeToCamel(patchParams, rule)).toThrowError( - 'Invalid value "1" supplied to "threat_query",Invalid value "1" supplied to "threat_indicator_path"' + 'threat_query: Expected string, received number, threat_indicator_path: Expected string, received number' ); }); @@ -77,7 +78,7 @@ describe('rule_converters', () => { const patchParams = { index: ['new-test-index'], language: 'lucene', - }; + } as PatchRuleRequestBody; const rule = getQueryRuleParams(); const patchedParams = patchTypeSpecificSnakeToCamel(patchParams, rule); expect(patchedParams).toEqual( @@ -92,10 +93,10 @@ describe('rule_converters', () => { const patchParams = { index: [1], language: 'non-language', - }; + } as PatchRuleRequestBody; const rule = getQueryRuleParams(); expect(() => patchTypeSpecificSnakeToCamel(patchParams, rule)).toThrowError( - 'Invalid value "1" supplied to "index",Invalid value "non-language" supplied to "language"' + "index.0: Expected string, received number, language: Invalid enum value. Expected 'kuery' | 'lucene', received 'non-language'" ); }); @@ -103,7 +104,7 @@ describe('rule_converters', () => { const patchParams = { index: ['new-test-index'], language: 'lucene', - }; + } as PatchRuleRequestBody; const rule = getSavedQueryRuleParams(); const patchedParams = patchTypeSpecificSnakeToCamel(patchParams, rule); expect(patchedParams).toEqual( @@ -118,10 +119,10 @@ describe('rule_converters', () => { const patchParams = { index: [1], language: 'non-language', - }; + } as PatchRuleRequestBody; const rule = getSavedQueryRuleParams(); expect(() => patchTypeSpecificSnakeToCamel(patchParams, rule)).toThrowError( - 'Invalid value "1" supplied to "index",Invalid value "non-language" supplied to "language"' + "index.0: Expected string, received number, language: Invalid enum value. Expected 'kuery' | 'lucene', received 'non-language'" ); }); @@ -150,10 +151,10 @@ describe('rule_converters', () => { field: ['host.name'], value: 'invalid', }, - }; + } as PatchRuleRequestBody; const rule = getThresholdRuleParams(); expect(() => patchTypeSpecificSnakeToCamel(patchParams, rule)).toThrowError( - 'Invalid value "invalid" supplied to "threshold,value"' + 'threshold.value: Expected number, received string' ); }); @@ -173,10 +174,10 @@ describe('rule_converters', () => { test('should reject invalid machine learning params when existing rule type is machine learning', () => { const patchParams = { anomaly_threshold: 'invalid', - }; + } as PatchRuleRequestBody; const rule = getMlRuleParams(); expect(() => patchTypeSpecificSnakeToCamel(patchParams, rule)).toThrowError( - 'Invalid value "invalid" supplied to "anomaly_threshold"' + 'anomaly_threshold: Expected number, received string' ); }); @@ -196,10 +197,10 @@ describe('rule_converters', () => { test('should reject invalid new terms params when existing rule type is new terms', () => { const patchParams = { new_terms_fields: 'invalid', - }; + } as PatchRuleRequestBody; const rule = getNewTermsRuleParams(); expect(() => patchTypeSpecificSnakeToCamel(patchParams, rule)).toThrowError( - 'Invalid value "invalid" supplied to "new_terms_fields"' + 'new_terms_fields: Expected array, received string' ); }); }); diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts index 2de991d700e701..b185a91b7ad374 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/normalization/rule_converters.ts @@ -7,11 +7,12 @@ import { v4 as uuidv4 } from 'uuid'; +import { stringifyZodError } from '@kbn/zod-helpers'; import { BadRequestError } from '@kbn/securitysolution-es-utils'; -import { validate, validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { ruleTypeMappings } from '@kbn/securitysolution-rules'; import type { ResolvedSanitizedRule, SanitizedRule } from '@kbn/alerting-plugin/common'; +import type { RequiredOptional } from '@kbn/zod-helpers'; import { DEFAULT_INDICATOR_SOURCE_PATH, DEFAULT_MAX_SIGNALS, @@ -28,14 +29,14 @@ import type { TypeSpecificResponse, } from '../../../../../common/api/detection_engine/model/rule_schema'; import { - EqlPatchParams, - EsqlPatchParams, - MachineLearningPatchParams, - NewTermsPatchParams, - QueryPatchParams, - SavedQueryPatchParams, - ThreatMatchPatchParams, - ThresholdPatchParams, + EqlRulePatchFields, + EsqlRulePatchFields, + MachineLearningRulePatchFields, + NewTermsRulePatchFields, + QueryRulePatchFields, + SavedQueryRulePatchFields, + ThreatMatchRulePatchFields, + ThresholdRulePatchFields, RuleResponse, } from '../../../../../common/api/detection_engine/model/rule_schema'; @@ -204,7 +205,7 @@ export const typeSpecificSnakeToCamel = ( }; const patchEqlParams = ( - params: EqlPatchParams, + params: EqlRulePatchFields, existingRule: EqlRuleParams ): EqlSpecificRuleParams => { return { @@ -221,7 +222,7 @@ const patchEqlParams = ( }; const patchEsqlParams = ( - params: EsqlPatchParams, + params: EsqlRulePatchFields, existingRule: EsqlRuleParams ): EsqlSpecificRuleParams => { return { @@ -232,7 +233,7 @@ const patchEsqlParams = ( }; const patchThreatMatchParams = ( - params: ThreatMatchPatchParams, + params: ThreatMatchRulePatchFields, existingRule: ThreatRuleParams ): ThreatSpecificRuleParams => { return { @@ -255,7 +256,7 @@ const patchThreatMatchParams = ( }; const patchQueryParams = ( - params: QueryPatchParams, + params: QueryRulePatchFields, existingRule: QueryRuleParams ): QuerySpecificRuleParams => { return { @@ -275,7 +276,7 @@ const patchQueryParams = ( }; const patchSavedQueryParams = ( - params: SavedQueryPatchParams, + params: SavedQueryRulePatchFields, existingRule: SavedQueryRuleParams ): SavedQuerySpecificRuleParams => { return { @@ -295,7 +296,7 @@ const patchSavedQueryParams = ( }; const patchThresholdParams = ( - params: ThresholdPatchParams, + params: ThresholdRulePatchFields, existingRule: ThresholdRuleParams ): ThresholdSpecificRuleParams => { return { @@ -313,7 +314,7 @@ const patchThresholdParams = ( }; const patchMachineLearningParams = ( - params: MachineLearningPatchParams, + params: MachineLearningRulePatchFields, existingRule: MachineLearningRuleParams ): MachineLearningSpecificRuleParams => { return { @@ -326,7 +327,7 @@ const patchMachineLearningParams = ( }; const patchNewTermsParams = ( - params: NewTermsPatchParams, + params: NewTermsRulePatchFields, existingRule: NewTermsRuleParams ): NewTermsSpecificRuleParams => { return { @@ -341,14 +342,6 @@ const patchNewTermsParams = ( }; }; -const parseValidationError = (error: string | null): BadRequestError => { - if (error != null) { - return new BadRequestError(error); - } else { - return new BadRequestError('unknown validation error'); - } -}; - export const patchTypeSpecificSnakeToCamel = ( params: PatchRuleRequestBody, existingRule: RuleParams @@ -360,60 +353,60 @@ export const patchTypeSpecificSnakeToCamel = ( // but would be assignable to the other rule types since they don't specify `event_category_override`. switch (existingRule.type) { case 'eql': { - const [validated, error] = validateNonExact(params, EqlPatchParams); - if (validated == null) { - throw parseValidationError(error); + const result = EqlRulePatchFields.safeParse(params); + if (!result.success) { + throw new BadRequestError(stringifyZodError(result.error)); } - return patchEqlParams(validated, existingRule); + return patchEqlParams(result.data, existingRule); } case 'esql': { - const [validated, error] = validateNonExact(params, EsqlPatchParams); - if (validated == null) { - throw parseValidationError(error); + const result = EsqlRulePatchFields.safeParse(params); + if (!result.success) { + throw new BadRequestError(stringifyZodError(result.error)); } - return patchEsqlParams(validated, existingRule); + return patchEsqlParams(result.data, existingRule); } case 'threat_match': { - const [validated, error] = validateNonExact(params, ThreatMatchPatchParams); - if (validated == null) { - throw parseValidationError(error); + const result = ThreatMatchRulePatchFields.safeParse(params); + if (!result.success) { + throw new BadRequestError(stringifyZodError(result.error)); } - return patchThreatMatchParams(validated, existingRule); + return patchThreatMatchParams(result.data, existingRule); } case 'query': { - const [validated, error] = validateNonExact(params, QueryPatchParams); - if (validated == null) { - throw parseValidationError(error); + const result = QueryRulePatchFields.safeParse(params); + if (!result.success) { + throw new BadRequestError(stringifyZodError(result.error)); } - return patchQueryParams(validated, existingRule); + return patchQueryParams(result.data, existingRule); } case 'saved_query': { - const [validated, error] = validateNonExact(params, SavedQueryPatchParams); - if (validated == null) { - throw parseValidationError(error); + const result = SavedQueryRulePatchFields.safeParse(params); + if (!result.success) { + throw new BadRequestError(stringifyZodError(result.error)); } - return patchSavedQueryParams(validated, existingRule); + return patchSavedQueryParams(result.data, existingRule); } case 'threshold': { - const [validated, error] = validateNonExact(params, ThresholdPatchParams); - if (validated == null) { - throw parseValidationError(error); + const result = ThresholdRulePatchFields.safeParse(params); + if (!result.success) { + throw new BadRequestError(stringifyZodError(result.error)); } - return patchThresholdParams(validated, existingRule); + return patchThresholdParams(result.data, existingRule); } case 'machine_learning': { - const [validated, error] = validateNonExact(params, MachineLearningPatchParams); - if (validated == null) { - throw parseValidationError(error); + const result = MachineLearningRulePatchFields.safeParse(params); + if (!result.success) { + throw new BadRequestError(stringifyZodError(result.error)); } - return patchMachineLearningParams(validated, existingRule); + return patchMachineLearningParams(result.data, existingRule); } case 'new_terms': { - const [validated, error] = validateNonExact(params, NewTermsPatchParams); - if (validated == null) { - throw parseValidationError(error); + const result = NewTermsRulePatchFields.safeParse(params); + if (!result.success) { + throw new BadRequestError(stringifyZodError(result.error)); } - return patchNewTermsParams(validated, existingRule); + return patchNewTermsParams(result.data, existingRule); } default: { return assertUnreachable(existingRule); @@ -433,7 +426,8 @@ export const convertPatchAPIToInternalSchema = ( const typeSpecificParams = patchTypeSpecificSnakeToCamel(nextParams, existingRule.params); const existingParams = existingRule.params; - const alertActions = nextParams.actions?.map(transformRuleToAlertAction) ?? existingRule.actions; + const alertActions = + nextParams.actions?.map((action) => transformRuleToAlertAction(action)) ?? existingRule.actions; const throttle = nextParams.throttle ?? transformFromAlertThrottle(existingRule); const actions = transformToActionFrequency(alertActions, throttle); @@ -494,7 +488,7 @@ export const convertCreateAPIToInternalSchema = ( const typeSpecificParams = typeSpecificSnakeToCamel(input); const newRuleId = input.rule_id ?? uuidv4(); - const alertActions = input.actions?.map(transformRuleToAlertAction) ?? []; + const alertActions = input.actions?.map((action) => transformRuleToAlertAction(action)) ?? []; const actions = transformToActionFrequency(alertActions, input.throttle); return { @@ -543,7 +537,9 @@ export const convertCreateAPIToInternalSchema = ( }; // Converts the internal rule data structure to the response API schema -export const typeSpecificCamelToSnake = (params: TypeSpecificRuleParams): TypeSpecificResponse => { +export const typeSpecificCamelToSnake = ( + params: TypeSpecificRuleParams +): RequiredOptional => { switch (params.type) { case 'eql': { return { @@ -687,7 +683,7 @@ export const commonParamsCamelToSnake = (params: BaseRuleParams) => { export const internalRuleToAPIResponse = ( rule: SanitizedRule | ResolvedSanitizedRule -): RuleResponse => { +): RequiredOptional => { const executionSummary = createRuleExecutionSummary(rule); const isResolvedRule = (obj: unknown): obj is ResolvedSanitizedRule => @@ -758,14 +754,9 @@ export const convertPrebuiltRuleAssetToRuleResponse = ( revision: 1, }; - const [rule, error] = validate( - { ...prebuiltRuleAssetDefaults, ...prebuiltRuleAsset, ...ruleResponseSpecificFields }, - RuleResponse - ); - - if (!rule) { - throw new Error(error); - } - - return rule; + return RuleResponse.parse({ + ...prebuiltRuleAssetDefaults, + ...prebuiltRuleAsset, + ...ruleResponseSpecificFields, + }); }; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.ts index 569e6f605a6c19..8a9370c64d0999 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/utils.ts @@ -9,26 +9,26 @@ import { partition } from 'lodash/fp'; import pMap from 'p-map'; import { v4 as uuidv4 } from 'uuid'; +import type { ActionsClient, FindActionResult } from '@kbn/actions-plugin/server'; +import type { FindResult, PartialRule } from '@kbn/alerting-plugin/server'; import type { SavedObjectsClientContract } from '@kbn/core/server'; import type { RuleAction } from '@kbn/securitysolution-io-ts-alerting-types'; -import type { PartialRule, FindResult } from '@kbn/alerting-plugin/server'; -import type { ActionsClient, FindActionResult } from '@kbn/actions-plugin/server'; -import type { - FindRulesResponse, - RuleToImport, -} from '../../../../../common/api/detection_engine/rule_management'; import type { AlertSuppression, AlertSuppressionCamel, InvestigationFields, RuleResponse, } from '../../../../../common/api/detection_engine/model/rule_schema'; +import type { + FindRulesResponse, + RuleToImport, +} from '../../../../../common/api/detection_engine/rule_management'; -import type { InvestigationFieldsCombined, RuleAlertType, RuleParams } from '../../rule_schema'; -import { isAlertType } from '../../rule_schema'; import type { BulkError, OutputError } from '../../routes/utils'; import { createBulkErrorObject } from '../../routes/utils'; +import type { InvestigationFieldsCombined, RuleAlertType, RuleParams } from '../../rule_schema'; +import { hasValidRuleType } from '../../rule_schema'; import { internalRuleToAPIResponse } from '../normalization/rule_converters'; type PromiseFromStreams = RuleToImport | Error; @@ -126,7 +126,7 @@ export const transformFindAlerts = (ruleFindResults: FindResult): Fi }; export const transform = (rule: PartialRule): RuleResponse | null => { - if (isAlertType(rule)) { + if (hasValidRuleType(rule)) { return internalRuleToAPIResponse(rule); } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts index eb442f5fc37bb2..07b9c9d0cbcd83 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.test.ts @@ -85,18 +85,17 @@ describe('validate', () => { describe('transformValidate', () => { test('it should do a validation correctly of a partial alert', () => { const ruleAlert = getRuleMock(getQueryRuleParams()); - const [validated, errors] = transformValidate(ruleAlert); + const validated = transformValidate(ruleAlert); expect(validated).toEqual(ruleOutput()); - expect(errors).toEqual(null); }); test('it should do an in-validation correctly of a partial alert', () => { const ruleAlert = getRuleMock(getQueryRuleParams()); // @ts-expect-error delete ruleAlert.name; - const [validated, errors] = transformValidate(ruleAlert); - expect(validated).toEqual(null); - expect(errors).toEqual('Invalid value "undefined" supplied to "name"'); + expect(() => { + transformValidate(ruleAlert); + }).toThrowError('Invalid input'); }); }); @@ -114,7 +113,7 @@ describe('validate', () => { const validatedOrError = transformValidateBulkError('rule-1', ruleAlert); const expected: BulkError = { error: { - message: 'Invalid value "undefined" supplied to "name"', + message: 'Invalid input', status_code: 500, }, rule_id: 'rule-1', diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts index c42f3f1546be6b..1e8931122f5c42 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_management/utils/validate.ts @@ -5,11 +5,10 @@ * 2.0. */ -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; - import type { PartialRule } from '@kbn/alerting-plugin/server'; import type { Rule } from '@kbn/alerting-plugin/common'; import { isEqual, xorWith } from 'lodash'; +import { stringifyZodError } from '@kbn/zod-helpers'; import { RESPONSE_ACTION_API_COMMANDS_TO_CONSOLE_COMMAND_MAP, RESPONSE_CONSOLE_ACTION_COMMANDS_TO_REQUIRED_AUTHZ, @@ -24,7 +23,7 @@ import type { } from '../../../../../common/api/detection_engine/model/rule_schema'; import { RuleResponse } from '../../../../../common/api/detection_engine/model/rule_schema'; import type { RuleParams, RuleAlertType, UnifiedQueryRuleParams } from '../../rule_schema'; -import { isAlertType } from '../../rule_schema'; +import { hasValidRuleType } from '../../rule_schema'; import type { BulkError } from '../../routes/utils'; import { createBulkErrorObject } from '../../routes/utils'; import { transform } from './utils'; @@ -34,33 +33,26 @@ import type { RuleResponseAction, } from '../../../../../common/api/detection_engine/model/rule_response_actions'; -export const transformValidate = ( - rule: PartialRule -): [RuleResponse, null] | [null, string] => { +export const transformValidate = (rule: PartialRule): RuleResponse => { const transformed = transform(rule); - if (transformed == null) { - return [null, 'Internal error transforming']; - } else { - return validateNonExact(transformed, RuleResponse); - } + return RuleResponse.parse(transformed); }; export const transformValidateBulkError = ( ruleId: string, rule: PartialRule ): RuleResponse | BulkError => { - if (isAlertType(rule)) { + if (hasValidRuleType(rule)) { const transformed = internalRuleToAPIResponse(rule); - const [validated, errors] = validateNonExact(transformed, RuleResponse); - if (errors != null || validated == null) { + const result = RuleResponse.safeParse(transformed); + if (!result.success) { return createBulkErrorObject({ ruleId, statusCode: 500, - message: errors ?? 'Internal error transforming', + message: stringifyZodError(result.error), }); - } else { - return validated; } + return result.data; } else { return createBulkErrorObject({ ruleId, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/client_for_executors/client.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/client_for_executors/client.ts index 84cdc041f9a884..101884b284ebcc 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/client_for_executors/client.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/client_for_executors/client.ts @@ -14,7 +14,6 @@ import type { PublicRuleResultService, } from '@kbn/alerting-plugin/server/types'; import type { - RuleExecutionMetrics, RuleExecutionSettings, RuleExecutionStatus, } from '../../../../../../../common/api/detection_engine/rule_monitoring'; @@ -38,6 +37,7 @@ import type { RuleExecutionContext, StatusChangeArgs, } from './client_interface'; +import type { RuleExecutionMetrics } from '../../../../../../../common/api/detection_engine/rule_monitoring/model'; export const createRuleExecutionLogClientForExecutors = ( settings: RuleExecutionSettings, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_writer.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_writer.ts index dfd01f5ad80af4..89696e7175a307 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_writer.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_monitoring/logic/rule_execution_log/event_log/event_log_writer.ts @@ -8,10 +8,6 @@ import { SavedObjectsUtils } from '@kbn/core/server'; import type { IEventLogService } from '@kbn/event-log-plugin/server'; import { SAVED_OBJECT_REL_PRIMARY } from '@kbn/event-log-plugin/server'; -import type { - RuleExecutionMetrics, - RuleExecutionStatus, -} from '../../../../../../../common/api/detection_engine/rule_monitoring'; import { LogLevel, logLevelFromExecutionStatus, @@ -19,6 +15,10 @@ import { RuleExecutionEventType, ruleExecutionStatusToNumber, } from '../../../../../../../common/api/detection_engine/rule_monitoring'; +import type { + RuleExecutionMetrics, + RuleExecutionStatus, +} from '../../../../../../../common/api/detection_engine/rule_monitoring/model'; import { RULE_SAVED_OBJECT_TYPE, RULE_EXECUTION_LOG_PROVIDER, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts index bbefafb1024238..9281c317ab2e0b 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_preview/api/preview_rules/route.ts @@ -13,6 +13,7 @@ import type { IRuleDataClient } from '@kbn/rule-registry-plugin/server'; import type { AlertInstanceContext, AlertInstanceState, + RuleAction, RuleTypeState, } from '@kbn/alerting-plugin/common'; import { parseDuration, DISABLE_FLAPPING_SETTINGS } from '@kbn/alerting-plugin/common'; @@ -29,7 +30,7 @@ import type { PreviewResponse, RulePreviewLogs, } from '../../../../../../common/api/detection_engine'; -import { previewRulesSchema } from '../../../../../../common/api/detection_engine'; +import { PreviewRulesSchema } from '../../../../../../common/api/detection_engine'; import type { StartPlugins, SetupPlugins } from '../../../../../plugin'; import { buildSiemResponse } from '../../../routes/utils'; @@ -39,7 +40,7 @@ import { createPreviewRuleExecutionLogger } from './preview_rule_execution_logge import { parseInterval } from '../../../rule_types/utils/utils'; import { buildMlAuthz } from '../../../../machine_learning/authz'; import { throwAuthzError } from '../../../../machine_learning/validation'; -import { buildRouteValidation } from '../../../../../utils/build_validation/route_validation'; +import { buildRouteValidationWithZod } from '../../../../../utils/build_validation/route_validation'; import { routeLimitedConcurrencyTag } from '../../../../../utils/route_limited_concurrency_tag'; import type { SecuritySolutionPluginRouter } from '../../../../../types'; @@ -90,7 +91,7 @@ export const previewRulesRoute = async ( .addVersion( { version: '2023-10-31', - validate: { request: { body: buildRouteValidation(previewRulesSchema) } }, + validate: { request: { body: buildRouteValidationWithZod(PreviewRulesSchema) } }, }, async (context, request, response): Promise> => { const siemResponse = buildSiemResponse(response); @@ -244,6 +245,10 @@ export const previewRulesRoute = async ( updatedBy: username ?? 'preview-updated-by', muteAll: false, snoozeSchedule: [], + // In Security Solution, action params are typed as Record, which is a correct type for action params, but we + // need to cast here to comply with the alerting types + actions: internalRule.actions as RuleAction[], }; let invocationStartTime; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_alert_type.ts index f7e73b49104c10..7003f7f32c062a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_alert_type.ts @@ -12,7 +12,7 @@ import type { RuleParams } from './rule_schemas'; export type RuleAlertType = SanitizedRule; -export const isAlertType = ( +export const hasValidRuleType = ( partialAlert: PartialRule ): partialAlert is RuleAlertType => { const ruleTypeValues = Object.values(ruleTypeMappings) as unknown as string[]; diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts index fbebf8374fabfb..cf124a3b775d3a 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_schema/model/rule_schemas.ts @@ -4,93 +4,89 @@ * 2.0; you may not use this file except in compliance with the Elastic License * 2.0. */ - -import * as t from 'io-ts'; - -import { - concurrentSearchesOrUndefined, - itemsPerSearchOrUndefined, - machine_learning_job_id_normalized, - RiskScore, - RiskScoreMapping, +import * as z from 'zod'; +import type { RuleActionArrayCamel, RuleActionNotifyWhen, RuleActionThrottle, - RuleIntervalFrom, - RuleIntervalTo, - Severity, - SeverityMapping, - threat_index, - threat_mapping, - threat_query, - threatIndicatorPathOrUndefined, } from '@kbn/securitysolution-io-ts-alerting-types'; -import { - SIGNALS_ID, +import type { EQL_RULE_TYPE_ID, ESQL_RULE_TYPE_ID, INDICATOR_RULE_TYPE_ID, ML_RULE_TYPE_ID, + NEW_TERMS_RULE_TYPE_ID, QUERY_RULE_TYPE_ID, - THRESHOLD_RULE_TYPE_ID, SAVED_QUERY_RULE_TYPE_ID, - NEW_TERMS_RULE_TYPE_ID, + SIGNALS_ID, + THRESHOLD_RULE_TYPE_ID, } from '@kbn/securitysolution-rules'; import type { SanitizedRuleConfig } from '@kbn/alerting-plugin/common'; -import { NonEmptyString } from '@kbn/securitysolution-io-ts-types'; +import { RuleResponseAction } from '../../../../../common/api/detection_engine'; +import type { + IsRuleEnabled, + RuleName, + RuleTagArray, +} from '../../../../../common/api/detection_engine/model/rule_schema'; import { AlertsIndex, AlertsIndexNamespace, - AlertSuppressionCamel, BuildingBlockType, - DataViewId, - EventCategoryOverride, - ExceptionListArray, - HistoryWindowStart, - IndexPatternArray, + RuleIntervalFrom, + RuleIntervalTo, + InvestigationFields, InvestigationGuide, - IsRuleEnabled, IsRuleImmutable, MaxSignals, - NewTermsFields, RelatedIntegrationArray, RequiredFieldArray, RuleAuthorArray, RuleDescription, + RuleExceptionList, RuleFalsePositiveArray, - RuleFilterArray, RuleLicense, RuleMetadata, - RuleName, RuleNameOverride, - RuleQuery, RuleReferenceArray, RuleSignatureId, - RuleTagArray, RuleVersion, SetupGuide, ThreatArray, - ThresholdNormalized, - TiebreakerField, TimelineTemplateId, TimelineTemplateTitle, - TimestampField, TimestampOverride, TimestampOverrideFallbackDisabled, - InvestigationFields, + RiskScore, + RiskScoreMapping, + Severity, + SeverityMapping, + ConcurrentSearches, + DataViewId, + EventCategoryOverride, + IndexPatternArray, + ItemsPerSearch, + KqlQueryLanguage, + RuleFilterArray, + RuleQuery, + SavedQueryId, + ThreatIndex, + ThreatIndicatorPath, + ThreatMapping, + ThreatQuery, + TiebreakerField, + TimestampField, + AlertSuppressionCamel, + ThresholdNormalized, + AnomalyThreshold, + HistoryWindowStart, + NewTermsFields, } from '../../../../../common/api/detection_engine/model/rule_schema'; -import { - savedIdOrUndefined, - saved_id, - anomaly_threshold, -} from '../../../../../common/api/detection_engine'; -import { SERVER_APP_ID } from '../../../../../common/constants'; -import { ResponseActionRuleParamsOrUndefined } from '../../../../../common/api/detection_engine/model/rule_response_actions'; +import type { SERVER_APP_ID } from '../../../../../common/constants'; // 8.10.x is mapped as an array of strings -export type LegacyInvestigationFields = t.TypeOf; -export const LegacyInvestigationFields = t.array(NonEmptyString); +export type LegacyInvestigationFields = z.infer; +export const LegacyInvestigationFields = z.array(z.string()); /* * In ESS 8.10.x "investigation_fields" are mapped as string[]. @@ -100,191 +96,203 @@ export const LegacyInvestigationFields = t.array(NonEmptyString); * but APIs will only support intended object format. * See PR 169061 */ -export type InvestigationFieldsCombined = t.TypeOf; -export const InvestigationFieldsCombined = t.union([ +export type InvestigationFieldsCombined = z.infer; +export const InvestigationFieldsCombined = z.union([ InvestigationFields, LegacyInvestigationFields, ]); -const nonEqlLanguages = t.keyof({ kuery: null, lucene: null }); +// Conversion to an interface has to be disabled for the entire file; otherwise, +// the resulting union would not be assignable to Alerting's RuleParams due to a +// TypeScript bug: https://github.com/microsoft/TypeScript/issues/15300 -export const baseRuleParams = t.exact( - t.type({ - author: RuleAuthorArray, - buildingBlockType: t.union([BuildingBlockType, t.undefined]), - description: RuleDescription, - namespace: t.union([AlertsIndexNamespace, t.undefined]), - note: t.union([InvestigationGuide, t.undefined]), - falsePositives: RuleFalsePositiveArray, - from: RuleIntervalFrom, - ruleId: RuleSignatureId, - investigationFields: t.union([InvestigationFieldsCombined, t.undefined]), - immutable: IsRuleImmutable, - license: t.union([RuleLicense, t.undefined]), - outputIndex: AlertsIndex, - timelineId: t.union([TimelineTemplateId, t.undefined]), - timelineTitle: t.union([TimelineTemplateTitle, t.undefined]), - meta: t.union([RuleMetadata, t.undefined]), - // maxSignals not used in ML rules but probably should be used - maxSignals: MaxSignals, - riskScore: RiskScore, - riskScoreMapping: RiskScoreMapping, - ruleNameOverride: t.union([RuleNameOverride, t.undefined]), - severity: Severity, - severityMapping: SeverityMapping, - timestampOverride: t.union([TimestampOverride, t.undefined]), - timestampOverrideFallbackDisabled: t.union([TimestampOverrideFallbackDisabled, t.undefined]), - threat: ThreatArray, - to: RuleIntervalTo, - references: RuleReferenceArray, - version: RuleVersion, - exceptionsList: ExceptionListArray, - relatedIntegrations: t.union([RelatedIntegrationArray, t.undefined]), - requiredFields: t.union([RequiredFieldArray, t.undefined]), - setup: t.union([SetupGuide, t.undefined]), - }) -); -export type BaseRuleParams = t.TypeOf; +export type BaseRuleParams = z.infer; +export const BaseRuleParams = z.object({ + author: RuleAuthorArray, + buildingBlockType: BuildingBlockType.optional(), + description: RuleDescription, + namespace: AlertsIndexNamespace.optional(), + note: InvestigationGuide.optional(), + falsePositives: RuleFalsePositiveArray, + from: RuleIntervalFrom, + ruleId: RuleSignatureId, + investigationFields: InvestigationFieldsCombined.optional(), + immutable: IsRuleImmutable, + license: RuleLicense.optional(), + outputIndex: AlertsIndex, + timelineId: TimelineTemplateId.optional(), + timelineTitle: TimelineTemplateTitle.optional(), + meta: RuleMetadata.optional(), + maxSignals: MaxSignals, + riskScore: RiskScore, + riskScoreMapping: RiskScoreMapping, + ruleNameOverride: RuleNameOverride.optional(), + severity: Severity, + severityMapping: SeverityMapping, + timestampOverride: TimestampOverride.optional(), + timestampOverrideFallbackDisabled: TimestampOverrideFallbackDisabled.optional(), + threat: ThreatArray, + to: RuleIntervalTo, + references: RuleReferenceArray, + version: RuleVersion, + exceptionsList: RuleExceptionList.array(), + relatedIntegrations: RelatedIntegrationArray.optional(), + requiredFields: RequiredFieldArray.optional(), + setup: SetupGuide.optional(), +}); -const eqlSpecificRuleParams = t.type({ - type: t.literal('eql'), - language: t.literal('eql'), - index: t.union([IndexPatternArray, t.undefined]), - dataViewId: t.union([DataViewId, t.undefined]), +export type EqlSpecificRuleParams = z.infer; +export const EqlSpecificRuleParams = z.object({ + type: z.literal('eql'), + language: z.literal('eql'), + index: IndexPatternArray.optional(), + dataViewId: DataViewId.optional(), query: RuleQuery, - filters: t.union([RuleFilterArray, t.undefined]), - eventCategoryOverride: t.union([EventCategoryOverride, t.undefined]), - timestampField: t.union([TimestampField, t.undefined]), - tiebreakerField: t.union([TiebreakerField, t.undefined]), + filters: RuleFilterArray.optional(), + eventCategoryOverride: EventCategoryOverride.optional(), + timestampField: TimestampField.optional(), + tiebreakerField: TiebreakerField.optional(), }); -export const eqlRuleParams = t.intersection([baseRuleParams, eqlSpecificRuleParams]); -export type EqlSpecificRuleParams = t.TypeOf; -export type EqlRuleParams = t.TypeOf; -const esqlSpecificRuleParams = t.type({ - type: t.literal('esql'), - language: t.literal('esql'), +export type EqlRuleParams = BaseRuleParams & EqlSpecificRuleParams; +export const EqlRuleParams = z.intersection(BaseRuleParams, EqlSpecificRuleParams); + +export type EsqlSpecificRuleParams = z.infer; +export const EsqlSpecificRuleParams = z.object({ + type: z.literal('esql'), + language: z.literal('esql'), query: RuleQuery, }); -export const esqlRuleParams = t.intersection([baseRuleParams, esqlSpecificRuleParams]); -export type EsqlSpecificRuleParams = t.TypeOf; -export type EsqlRuleParams = t.TypeOf; -const threatSpecificRuleParams = t.type({ - type: t.literal('threat_match'), - language: nonEqlLanguages, - index: t.union([IndexPatternArray, t.undefined]), +export type EsqlRuleParams = BaseRuleParams & EsqlSpecificRuleParams; +export const EsqlRuleParams = z.intersection(BaseRuleParams, EsqlSpecificRuleParams); + +export type ThreatSpecificRuleParams = z.infer; +export const ThreatSpecificRuleParams = z.object({ + type: z.literal('threat_match'), + language: KqlQueryLanguage, + index: IndexPatternArray.optional(), query: RuleQuery, - filters: t.union([RuleFilterArray, t.undefined]), - savedId: savedIdOrUndefined, - threatFilters: t.union([RuleFilterArray, t.undefined]), - threatQuery: threat_query, - threatMapping: threat_mapping, - threatLanguage: t.union([nonEqlLanguages, t.undefined]), - threatIndex: threat_index, - threatIndicatorPath: threatIndicatorPathOrUndefined, - concurrentSearches: concurrentSearchesOrUndefined, - itemsPerSearch: itemsPerSearchOrUndefined, - dataViewId: t.union([DataViewId, t.undefined]), + filters: RuleFilterArray.optional(), + savedId: SavedQueryId.optional(), + threatFilters: RuleFilterArray.optional(), + threatQuery: ThreatQuery, + threatMapping: ThreatMapping, + threatLanguage: KqlQueryLanguage.optional(), + threatIndex: ThreatIndex, + threatIndicatorPath: ThreatIndicatorPath.optional(), + concurrentSearches: ConcurrentSearches.optional(), + itemsPerSearch: ItemsPerSearch.optional(), + dataViewId: DataViewId.optional(), }); -export const threatRuleParams = t.intersection([baseRuleParams, threatSpecificRuleParams]); -export type ThreatSpecificRuleParams = t.TypeOf; -export type ThreatRuleParams = t.TypeOf; -const querySpecificRuleParams = t.exact( - t.type({ - type: t.literal('query'), - language: nonEqlLanguages, - index: t.union([IndexPatternArray, t.undefined]), - query: RuleQuery, - filters: t.union([RuleFilterArray, t.undefined]), - savedId: savedIdOrUndefined, - dataViewId: t.union([DataViewId, t.undefined]), - responseActions: ResponseActionRuleParamsOrUndefined, - alertSuppression: t.union([AlertSuppressionCamel, t.undefined]), - }) -); -export const queryRuleParams = t.intersection([baseRuleParams, querySpecificRuleParams]); -export type QuerySpecificRuleParams = t.TypeOf; -export type QueryRuleParams = t.TypeOf; +export type ThreatRuleParams = BaseRuleParams & ThreatSpecificRuleParams; +export const ThreatRuleParams = z.intersection(BaseRuleParams, ThreatSpecificRuleParams); -const savedQuerySpecificRuleParams = t.type({ - type: t.literal('saved_query'), - // Having language, query, and filters possibly defined adds more code confusion and probably user confusion - // if the saved object gets deleted for some reason - language: nonEqlLanguages, - index: t.union([IndexPatternArray, t.undefined]), - dataViewId: t.union([DataViewId, t.undefined]), - query: t.union([RuleQuery, t.undefined]), - filters: t.union([RuleFilterArray, t.undefined]), - savedId: saved_id, - responseActions: ResponseActionRuleParamsOrUndefined, - alertSuppression: t.union([AlertSuppressionCamel, t.undefined]), +export type QuerySpecificRuleParams = z.infer; +export const QuerySpecificRuleParams = z.object({ + type: z.literal('query'), + language: KqlQueryLanguage, + index: IndexPatternArray.optional(), + query: RuleQuery, + filters: RuleFilterArray.optional(), + savedId: SavedQueryId.optional(), + dataViewId: DataViewId.optional(), + responseActions: z.array(RuleResponseAction).optional(), + alertSuppression: AlertSuppressionCamel.optional(), }); -export const savedQueryRuleParams = t.intersection([baseRuleParams, savedQuerySpecificRuleParams]); -export type SavedQuerySpecificRuleParams = t.TypeOf; -export type SavedQueryRuleParams = t.TypeOf; -export const unifiedQueryRuleParams = t.intersection([ - baseRuleParams, - t.union([querySpecificRuleParams, savedQuerySpecificRuleParams]), -]); -export type UnifiedQueryRuleParams = t.TypeOf; +export type QueryRuleParams = BaseRuleParams & QuerySpecificRuleParams; +export const QueryRuleParams = z.intersection(BaseRuleParams, QuerySpecificRuleParams); -const thresholdSpecificRuleParams = t.type({ - type: t.literal('threshold'), - language: nonEqlLanguages, - index: t.union([IndexPatternArray, t.undefined]), +export type SavedQuerySpecificRuleParams = z.infer; +export const SavedQuerySpecificRuleParams = z.object({ + type: z.literal('saved_query'), + language: KqlQueryLanguage, + index: IndexPatternArray.optional(), + dataViewId: DataViewId.optional(), + query: RuleQuery.optional(), + filters: RuleFilterArray.optional(), + savedId: SavedQueryId, + responseActions: z.array(RuleResponseAction).optional(), + alertSuppression: AlertSuppressionCamel.optional(), +}); + +export type SavedQueryRuleParams = BaseRuleParams & SavedQuerySpecificRuleParams; +export const SavedQueryRuleParams = z.intersection(BaseRuleParams, SavedQuerySpecificRuleParams); + +export type UnifiedQueryRuleParams = z.infer; +export const UnifiedQueryRuleParams = z.intersection( + BaseRuleParams, + z.union([QuerySpecificRuleParams, SavedQuerySpecificRuleParams]) +); + +export type ThresholdSpecificRuleParams = z.infer; +export const ThresholdSpecificRuleParams = z.object({ + type: z.literal('threshold'), + language: KqlQueryLanguage, + index: IndexPatternArray.optional(), query: RuleQuery, - filters: t.union([RuleFilterArray, t.undefined]), - savedId: savedIdOrUndefined, + filters: RuleFilterArray.optional(), + savedId: SavedQueryId.optional(), threshold: ThresholdNormalized, - dataViewId: t.union([DataViewId, t.undefined]), + dataViewId: DataViewId.optional(), }); -export const thresholdRuleParams = t.intersection([baseRuleParams, thresholdSpecificRuleParams]); -export type ThresholdSpecificRuleParams = t.TypeOf; -export type ThresholdRuleParams = t.TypeOf; -const machineLearningSpecificRuleParams = t.type({ - type: t.literal('machine_learning'), - anomalyThreshold: anomaly_threshold, - machineLearningJobId: machine_learning_job_id_normalized, +export type ThresholdRuleParams = BaseRuleParams & ThresholdSpecificRuleParams; +export const ThresholdRuleParams = z.intersection(BaseRuleParams, ThresholdSpecificRuleParams); + +export type MachineLearningSpecificRuleParams = z.infer; +export const MachineLearningSpecificRuleParams = z.object({ + type: z.literal('machine_learning'), + anomalyThreshold: AnomalyThreshold, + machineLearningJobId: z.array(z.string()), }); -export const machineLearningRuleParams = t.intersection([ - baseRuleParams, - machineLearningSpecificRuleParams, -]); -export type MachineLearningSpecificRuleParams = t.TypeOf; -export type MachineLearningRuleParams = t.TypeOf; -const newTermsSpecificRuleParams = t.type({ - type: t.literal('new_terms'), +export type MachineLearningRuleParams = BaseRuleParams & MachineLearningSpecificRuleParams; +export const MachineLearningRuleParams = z.intersection( + BaseRuleParams, + MachineLearningSpecificRuleParams +); + +export type NewTermsSpecificRuleParams = z.infer; +export const NewTermsSpecificRuleParams = z.object({ + type: z.literal('new_terms'), query: RuleQuery, newTermsFields: NewTermsFields, historyWindowStart: HistoryWindowStart, - index: t.union([IndexPatternArray, t.undefined]), - filters: t.union([RuleFilterArray, t.undefined]), - language: nonEqlLanguages, - dataViewId: t.union([DataViewId, t.undefined]), + index: IndexPatternArray.optional(), + filters: RuleFilterArray.optional(), + language: KqlQueryLanguage, + dataViewId: DataViewId.optional(), }); -export const newTermsRuleParams = t.intersection([baseRuleParams, newTermsSpecificRuleParams]); -export type NewTermsSpecificRuleParams = t.TypeOf; -export type NewTermsRuleParams = t.TypeOf; -export const typeSpecificRuleParams = t.union([ - eqlSpecificRuleParams, - esqlSpecificRuleParams, - threatSpecificRuleParams, - querySpecificRuleParams, - savedQuerySpecificRuleParams, - thresholdSpecificRuleParams, - machineLearningSpecificRuleParams, - newTermsSpecificRuleParams, +export type NewTermsRuleParams = BaseRuleParams & NewTermsSpecificRuleParams; +export const NewTermsRuleParams = z.intersection(BaseRuleParams, NewTermsSpecificRuleParams); + +export type TypeSpecificRuleParams = z.infer; +export const TypeSpecificRuleParams = z.union([ + EqlSpecificRuleParams, + EsqlSpecificRuleParams, + ThreatSpecificRuleParams, + QuerySpecificRuleParams, + SavedQuerySpecificRuleParams, + ThresholdSpecificRuleParams, + MachineLearningSpecificRuleParams, + NewTermsSpecificRuleParams, ]); -export type TypeSpecificRuleParams = t.TypeOf; -export const ruleParams = t.intersection([baseRuleParams, typeSpecificRuleParams]); -export type RuleParams = t.TypeOf; +export type RuleParams = z.infer; +export const RuleParams = z.union([ + EqlRuleParams, + EsqlRuleParams, + ThreatRuleParams, + QueryRuleParams, + SavedQueryRuleParams, + ThresholdRuleParams, + MachineLearningRuleParams, + NewTermsRuleParams, +]); export interface CompleteRule { alertId: string; @@ -292,55 +300,40 @@ export interface CompleteRule { ruleConfig: SanitizedRuleConfig; } -export const allRuleTypes = t.union([ - t.literal(SIGNALS_ID), - t.literal(EQL_RULE_TYPE_ID), - t.literal(ESQL_RULE_TYPE_ID), - t.literal(INDICATOR_RULE_TYPE_ID), - t.literal(ML_RULE_TYPE_ID), - t.literal(QUERY_RULE_TYPE_ID), - t.literal(SAVED_QUERY_RULE_TYPE_ID), - t.literal(THRESHOLD_RULE_TYPE_ID), - t.literal(NEW_TERMS_RULE_TYPE_ID), -]); +export type AllRuleTypes = + | typeof SIGNALS_ID + | typeof EQL_RULE_TYPE_ID + | typeof ESQL_RULE_TYPE_ID + | typeof INDICATOR_RULE_TYPE_ID + | typeof ML_RULE_TYPE_ID + | typeof QUERY_RULE_TYPE_ID + | typeof SAVED_QUERY_RULE_TYPE_ID + | typeof THRESHOLD_RULE_TYPE_ID + | typeof NEW_TERMS_RULE_TYPE_ID; -const internalRuleCreateRequired = t.type({ - name: RuleName, - tags: RuleTagArray, - alertTypeId: allRuleTypes, - consumer: t.literal(SERVER_APP_ID), - schedule: t.type({ - interval: t.string, - }), - enabled: IsRuleEnabled, - actions: RuleActionArrayCamel, - params: ruleParams, -}); -const internalRuleCreateOptional = t.partial({ - throttle: t.union([RuleActionThrottle, t.null]), - notifyWhen: t.union([RuleActionNotifyWhen, t.null]), -}); -export const internalRuleCreate = t.intersection([ - internalRuleCreateOptional, - internalRuleCreateRequired, -]); -export type InternalRuleCreate = t.TypeOf; +export interface InternalRuleCreate { + name: RuleName; + tags: RuleTagArray; + alertTypeId: AllRuleTypes; + consumer: typeof SERVER_APP_ID; + schedule: { + interval: string; + }; + enabled: IsRuleEnabled; + actions: RuleActionArrayCamel; + params: RuleParams; + throttle?: RuleActionThrottle | null; + notifyWhen?: RuleActionNotifyWhen | null; +} -const internalRuleUpdateRequired = t.type({ - name: RuleName, - tags: RuleTagArray, - schedule: t.type({ - interval: t.string, - }), - actions: RuleActionArrayCamel, - params: ruleParams, -}); -const internalRuleUpdateOptional = t.partial({ - throttle: t.union([RuleActionThrottle, t.null]), - notifyWhen: t.union([RuleActionNotifyWhen, t.null]), -}); -export const internalRuleUpdate = t.intersection([ - internalRuleUpdateOptional, - internalRuleUpdateRequired, -]); -export type InternalRuleUpdate = t.TypeOf; +export interface InternalRuleUpdate { + name: RuleName; + tags: RuleTagArray; + schedule: { + interval: string; + }; + actions: RuleActionArrayCamel; + params: RuleParams; + throttle?: RuleActionThrottle | null; + notifyWhen?: RuleActionNotifyWhen | null; +} diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts index ffdeba16e3bf20..c457afeb48a92c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/eql/create_eql_alert_type.ts @@ -5,13 +5,11 @@ * 2.0. */ -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { EQL_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { EqlRuleParams } from '../../rule_schema'; -import { eqlRuleParams } from '../../rule_schema'; +import { EqlRuleParams } from '../../rule_schema'; import { eqlExecutor } from './eql'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; import { validateIndexPatterns } from '../utils'; @@ -26,14 +24,7 @@ export const createEqlAlertType = ( validate: { params: { validate: (object: unknown) => { - const [validated, errors] = validateNonExact(object, eqlRuleParams); - if (errors != null) { - throw new Error(errors); - } - if (validated == null) { - throw new Error('Validation of rule params failed'); - } - return validated; + return EqlRuleParams.parse(object); }, /** * validate rule params when rule is bulk edited (update and created in future as well) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts index 18f752a4a0d975..5672190d3ec005 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/create_esql_alert_type.ts @@ -5,13 +5,11 @@ * 2.0. */ -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { ESQL_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { EsqlRuleParams } from '../../rule_schema'; -import { esqlRuleParams } from '../../rule_schema'; +import { EsqlRuleParams } from '../../rule_schema'; import { esqlExecutor } from './esql'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; @@ -25,14 +23,7 @@ export const createEsqlAlertType = ( validate: { params: { validate: (object: unknown) => { - const [validated, errors] = validateNonExact(object, esqlRuleParams); - if (errors != null) { - throw new Error(errors); - } - if (validated == null) { - throw new Error('Validation of rule params failed'); - } - return validated; + return EsqlRuleParams.parse(object); }, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts index 73a9cbe6b93a9c..64ed0560f36099 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/esql/esql.ts @@ -148,6 +148,7 @@ export const esqlExecutor = async ({ if (bulkCreateResult.alertsWereTruncated) { result.warningMessages.push(getMaxSignalsWarning()); + break; } // no more results will be found diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts index 50187155e4fddf..1c3907d8109a33 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/indicator_match/create_indicator_match_alert_type.ts @@ -5,14 +5,12 @@ * 2.0. */ -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { INDICATOR_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { ThreatRuleParams } from '../../rule_schema'; -import { threatRuleParams } from '../../rule_schema'; +import { ThreatRuleParams } from '../../rule_schema'; import { indicatorMatchExecutor } from './indicator_match'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; import { validateIndexPatterns } from '../utils'; @@ -28,14 +26,7 @@ export const createIndicatorMatchAlertType = ( validate: { params: { validate: (object: unknown) => { - const [validated, errors] = validateNonExact(object, threatRuleParams); - if (errors != null) { - throw new Error(errors); - } - if (validated == null) { - throw new Error('Validation of rule params failed'); - } - return validated; + return ThreatRuleParams.parse(object); }, /** * validate rule params when rule is bulk edited (update and created in future as well) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts index 33a87c13523599..1fb9527b04b80d 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/ml/create_ml_alert_type.ts @@ -5,14 +5,12 @@ * 2.0. */ -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { ML_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { MachineLearningRuleParams } from '../../rule_schema'; -import { machineLearningRuleParams } from '../../rule_schema'; +import { MachineLearningRuleParams } from '../../rule_schema'; import { mlExecutor } from './ml'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; @@ -26,14 +24,7 @@ export const createMlAlertType = ( validate: { params: { validate: (object: unknown) => { - const [validated, errors] = validateNonExact(object, machineLearningRuleParams); - if (errors != null) { - throw new Error(errors); - } - if (validated == null) { - throw new Error('Validation of rule params failed'); - } - return validated; + return MachineLearningRuleParams.parse(object); }, }, }, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts index 147314d2640a56..88212b42fe7137 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/new_terms/create_new_terms_alert_type.ts @@ -5,13 +5,11 @@ * 2.0. */ -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { NEW_TERMS_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { NewTermsRuleParams } from '../../rule_schema'; -import { newTermsRuleParams } from '../../rule_schema'; +import { NewTermsRuleParams } from '../../rule_schema'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; import { singleSearchAfter } from '../utils/single_search_after'; import { getFilter } from '../utils/get_filter'; @@ -54,13 +52,7 @@ export const createNewTermsAlertType = ( validate: { params: { validate: (object: unknown) => { - const [validated, errors] = validateNonExact(object, newTermsRuleParams); - if (errors != null) { - throw new Error(errors); - } - if (validated == null) { - throw new Error('Validation of rule params failed'); - } + const validated = NewTermsRuleParams.parse(object); validateHistoryWindowStart({ historyWindowStart: validated.historyWindowStart, from: validated.from, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/alert_suppression/group_and_bulk_create.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/alert_suppression/group_and_bulk_create.ts index 54bc3d0e5cc471..a336c717224d22 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/alert_suppression/group_and_bulk_create.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/alert_suppression/group_and_bulk_create.ts @@ -26,12 +26,10 @@ import { singleSearchAfter } from '../../utils/single_search_after'; import { bulkCreateWithSuppression } from './bulk_create_with_suppression'; import type { UnifiedQueryRuleParams } from '../../../rule_schema'; import type { BuildReasonMessage } from '../../utils/reason_formatters'; -import { - AlertSuppressionMissingFieldsStrategy, - DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY, -} from '../../../../../../common/api/detection_engine/model/rule_schema'; +import { AlertSuppressionMissingFieldsStrategyEnum } from '../../../../../../common/api/detection_engine/model/rule_schema'; import { bulkCreateUnsuppressedAlerts } from './bulk_create_unsuppressed_alerts'; import type { ITelemetryEventsSender } from '../../../../telemetry/sender'; +import { DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY } from '../../../../../../common/detection_engine/constants'; export interface BucketHistory { key: Record; @@ -171,7 +169,7 @@ export const groupAndBulkCreate = async ({ const suppressOnMissingFields = (runOpts.completeRule.ruleParams.alertSuppression?.missingFieldsStrategy ?? DEFAULT_SUPPRESSION_MISSING_FIELDS_STRATEGY) === - AlertSuppressionMissingFieldsStrategy.Suppress; + AlertSuppressionMissingFieldsStrategyEnum.suppress; const groupingAggregation = buildGroupByFieldAggregation({ groupByFields, diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.ts index ae0a9187922a53..da5b0631cd98b5 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/query/create_query_alert_type.ts @@ -5,13 +5,11 @@ * 2.0. */ -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; import type { BucketHistory } from './alert_suppression/group_and_bulk_create'; -import type { UnifiedQueryRuleParams } from '../../rule_schema'; -import { unifiedQueryRuleParams } from '../../rule_schema'; +import { UnifiedQueryRuleParams } from '../../rule_schema'; import { queryExecutor } from './query'; import type { CreateQueryRuleOptions, SecurityAlertType } from '../types'; import { validateIndexPatterns } from '../utils'; @@ -39,14 +37,7 @@ export const createQueryAlertType = ( validate: { params: { validate: (object: unknown) => { - const [validated, errors] = validateNonExact(object, unifiedQueryRuleParams); - if (errors != null) { - throw new Error(errors); - } - if (validated == null) { - throw new Error('Validation of rule params failed'); - } - return validated; + return UnifiedQueryRuleParams.parse(object); }, /** * validate rule params when rule is bulk edited (update and created in future as well) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts index 2c5855747636bb..4297a24fa8bd3c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/threshold/create_threshold_alert_type.ts @@ -5,14 +5,12 @@ * 2.0. */ -import { validateNonExact } from '@kbn/securitysolution-io-ts-utils'; import { THRESHOLD_RULE_TYPE_ID } from '@kbn/securitysolution-rules'; import { DEFAULT_APP_CATEGORIES } from '@kbn/core-application-common'; import { SERVER_APP_ID } from '../../../../../common/constants'; -import type { ThresholdRuleParams } from '../../rule_schema'; -import { thresholdRuleParams } from '../../rule_schema'; +import { ThresholdRuleParams } from '../../rule_schema'; import { thresholdExecutor } from './threshold'; import type { ThresholdAlertState } from './types'; import type { CreateRuleOptions, SecurityAlertType } from '../types'; @@ -28,14 +26,7 @@ export const createThresholdAlertType = ( validate: { params: { validate: (object: unknown): ThresholdRuleParams => { - const [validated, errors] = validateNonExact(object, thresholdRuleParams); - if (errors != null) { - throw new Error(errors); - } - if (validated == null) { - throw new Error('Validation of rule params failed'); - } - return validated; + return ThresholdRuleParams.parse(object); }, /** * validate rule params when rule is bulk edited (update and created in future as well) diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts index 832ade89afa906..c9159c1739c37c 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/rule_types/types.ts @@ -44,12 +44,7 @@ import type { IRuleExecutionLogForExecutors, IRuleMonitoringService } from '../r import type { RefreshTypes } from '../types'; import type { Status } from '../../../../common/api/detection_engine'; -import type { - BaseHit, - RuleAlertAction, - SearchTypes, - EqlSequence, -} from '../../../../common/detection_engine/types'; +import type { BaseHit, SearchTypes, EqlSequence } from '../../../../common/detection_engine/types'; import type { GenericBulkCreateResponse } from './factories'; import type { BuildReasonMessage } from './utils/reason_formatters'; import type { @@ -57,7 +52,10 @@ import type { DetectionAlert, WrappedFieldsLatest, } from '../../../../common/api/detection_engine/model/alerts'; -import type { RuleResponse } from '../../../../common/api/detection_engine/model/rule_schema'; +import type { + RuleAction, + RuleResponse, +} from '../../../../common/api/detection_engine/model/rule_schema'; import type { EnrichEvents } from './utils/enrichments/types'; import type { ThresholdResult } from './threshold/types'; @@ -305,7 +303,7 @@ export interface SignalHit { } export interface AlertAttributes { - actions: RuleAlertAction[]; + actions: RuleAction[]; alertTypeId: string; enabled: boolean; name: string; diff --git a/x-pack/plugins/security_solution/server/utils/build_validation/route_validation.ts b/x-pack/plugins/security_solution/server/utils/build_validation/route_validation.ts index a6e41257123ab4..7775186cde97f1 100644 --- a/x-pack/plugins/security_solution/server/utils/build_validation/route_validation.ts +++ b/x-pack/plugins/security_solution/server/utils/build_validation/route_validation.ts @@ -15,7 +15,7 @@ import type { RouteValidationError, } from '@kbn/core/server'; import type { TypeOf, ZodType } from 'zod'; -import { stringifyZodError } from '@kbn/securitysolution-es-utils'; +import { stringifyZodError } from '@kbn/zod-helpers'; import type { GenericIntersectionC } from '../runtime_types'; import { excess } from '../runtime_types'; diff --git a/x-pack/plugins/security_solution/tsconfig.json b/x-pack/plugins/security_solution/tsconfig.json index 3f25ce9922391c..59acd2f3422cb9 100644 --- a/x-pack/plugins/security_solution/tsconfig.json +++ b/x-pack/plugins/security_solution/tsconfig.json @@ -14,11 +14,7 @@ "public/**/*.json", "../../../typings/**/*" ], - "exclude": [ - "target/**/*", - "**/cypress/**", - "public/management/cypress.config.ts" - ], + "exclude": ["target/**/*", "**/cypress/**", "public/management/cypress.config.ts"], "kbn_references": [ "@kbn/core", { @@ -179,6 +175,7 @@ "@kbn/es", "@kbn/react-kibana-mount", "@kbn/unified-doc-viewer-plugin", - "@kbn/shared-ux-error-boundary" + "@kbn/shared-ux-error-boundary", + "@kbn/zod-helpers" ] } diff --git a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx index 163660755a3bec..d53281dbf6de13 100644 --- a/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx +++ b/x-pack/plugins/serverless_observability/public/components/side_navigation/index.tsx @@ -33,6 +33,14 @@ const navigationTree: NavigationTreeDefinition = { defaultMessage: 'Log Explorer', }), link: 'observability-log-explorer', + renderAs: 'item', + children: [ + { + // This is to show "discover" breadcrumbs when navigating from "log explorer" to "discover" + link: 'discover', + sideNavStatus: 'hidden', + }, + ], }, { title: i18n.translate('xpack.serverlessObservability.nav.dashboards', { diff --git a/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx b/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx index 3c59d064d72cc4..207917013c7e55 100644 --- a/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/overview.test.tsx @@ -5,9 +5,15 @@ * 2.0. */ import React from 'react'; +import { useLocation } from 'react-router-dom'; import { render, core } from '../../test/test_utils'; import { ElasticsearchOverview as Overview } from './overview'; +jest.mock('react-router-dom', () => ({ + ...jest.requireActual('react-router-dom'), + useLocation: jest.fn(), +})); + describe('', () => { beforeEach(() => { core.http.fetch.mockImplementation((url) => { @@ -29,6 +35,10 @@ describe('', () => { } }); }); + const pathname = '/app/elasticsearch'; + (useLocation as jest.Mock).mockImplementationOnce(() => ({ + pathname, + })); }); test('renders without throwing an error', () => { diff --git a/x-pack/plugins/serverless_search/public/application/components/overview.tsx b/x-pack/plugins/serverless_search/public/application/components/overview.tsx index cd5faa1ba63e48..bf66ae62855a56 100644 --- a/x-pack/plugins/serverless_search/public/application/components/overview.tsx +++ b/x-pack/plugins/serverless_search/public/application/components/overview.tsx @@ -32,13 +32,14 @@ import { getConsoleRequest, } from '@kbn/search-api-panels'; -import React, { useMemo, useState } from 'react'; +import React, { useEffect, useMemo, useState } from 'react'; import type { LanguageDefinition, LanguageDefinitionSnippetArguments, } from '@kbn/search-api-panels'; import { useQuery } from '@tanstack/react-query'; import { Connector } from '@kbn/search-connectors'; +import { useLocation } from 'react-router-dom'; import { docLinks } from '../../../common/doc_links'; import { PLUGIN_ID } from '../../../common'; import { useKibanaServices } from '../hooks/use_kibana'; @@ -70,6 +71,16 @@ export const ElasticsearchOverview = () => { apiKey: clientApiKey, cloudId, }; + const { hash } = useLocation(); + useEffect(() => { + if (hash) { + const id = hash.replace('#', ''); + const element = document.getElementById(id); + if (element) { + element.scrollIntoView({ behavior: 'smooth' }); + } + } + }, [hash]); const { data: _data } = useQuery({ queryKey: ['fetchConnectors'], @@ -279,6 +290,7 @@ export const ElasticsearchOverview = () => { /> - + + + + + + + diff --git a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_retention.tsx b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_retention.tsx index c45e49e86db70e..e9b98c48d7bad9 100644 --- a/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_retention.tsx +++ b/x-pack/plugins/snapshot_restore/public/application/components/policy_form/steps/step_retention.tsx @@ -18,6 +18,7 @@ import { EuiSelect, } from '@elastic/eui'; +import { i18n } from '@kbn/i18n'; import { SlmPolicyPayload } from '../../../../../common/types'; import { TIME_UNITS } from '../../../../../common/constants'; import { StepProps } from '.'; @@ -102,6 +103,12 @@ export const PolicyStepRetention: React.FunctionComponent = ({ }} data-test-subj="expireAfterValueInput" min={0} + aria-label={i18n.translate( + 'xpack.snapshotRestore.policyForm.stepRetention.expireAfterAriaLabel', + { + defaultMessage: 'Expiration time input', + } + )} /> @@ -116,6 +123,12 @@ export const PolicyStepRetention: React.FunctionComponent = ({ }); }} data-test-subj="expireAfterUnitSelect" + aria-label={i18n.translate( + 'xpack.snapshotRestore.policyForm.stepRetention.expireAfterUnitsAriaLabel', + { + defaultMessage: 'Expiration time units selection', + } + )} /> diff --git a/x-pack/plugins/synthetics/common/constants/synthetics/rest_api.ts b/x-pack/plugins/synthetics/common/constants/synthetics/rest_api.ts index 40ae2656e2b26c..6f7a1855ac4025 100644 --- a/x-pack/plugins/synthetics/common/constants/synthetics/rest_api.ts +++ b/x-pack/plugins/synthetics/common/constants/synthetics/rest_api.ts @@ -6,6 +6,9 @@ */ export enum SYNTHETICS_API_URLS { + // public apis + PARAMS = `/api/synthetics/params`, + // Service end points INDEX_TEMPLATES = '/internal/synthetics/service/index_templates', SERVICE_LOCATIONS = '/internal/uptime/service/locations', @@ -24,7 +27,6 @@ export enum SYNTHETICS_API_URLS { PING_STATUSES = '/internal/synthetics/ping_statuses', OVERVIEW_STATUS = `/internal/synthetics/overview_status`, INDEX_SIZE = `/internal/synthetics/index_size`, - PARAMS = `/internal/synthetics/params`, AGENT_POLICIES = `/internal/synthetics/agent_policies`, PRIVATE_LOCATIONS = `/internal/synthetics/private_locations`, PRIVATE_LOCATIONS_MONITORS = `/internal/synthetics/private_locations/monitors`, diff --git a/x-pack/plugins/synthetics/common/constants/ui.ts b/x-pack/plugins/synthetics/common/constants/ui.ts index 64259a676189c6..8f3ee8f3b903b2 100644 --- a/x-pack/plugins/synthetics/common/constants/ui.ts +++ b/x-pack/plugins/synthetics/common/constants/ui.ts @@ -73,3 +73,5 @@ export const SYNTHETICS_INDEX_PATTERN = 'synthetics-*'; export const LICENSE_NOT_ACTIVE_ERROR = 'License not active'; export const LICENSE_MISSING_ERROR = 'Missing license information'; export const LICENSE_NOT_SUPPORTED_ERROR = 'License not supported'; + +export const INITIAL_REST_VERSION = '2023-10-31'; diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/stderr_logs.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/stderr_logs.tsx index 6170c116d9e633..b4a28335ce132c 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/stderr_logs.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/common/components/stderr_logs.tsx @@ -139,6 +139,7 @@ export const StdErrorLogs = ({ }} pagination={{ pageSize, + pageSizeOptions: [2, 5, 10, 20, 50], }} /> diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/add_param_flyout.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/add_param_flyout.tsx index c79e5aec2177a1..3fd17335d2ea5f 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/add_param_flyout.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/add_param_flyout.tsx @@ -108,8 +108,9 @@ export const AddParamFlyout = ({ useEffect(() => { if (isEditingItem) { + const { id: _id, ...dataToEdit } = isEditingItem; setIsFlyoutVisible(true); - form.reset(isEditingItem); + form.reset(dataToEdit); } // no need to add form value, it keeps changing on reset // eslint-disable-next-line react-hooks/exhaustive-deps diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx b/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx index aa89829380044c..942afb91cfe48c 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx +++ b/x-pack/plugins/synthetics/public/apps/synthetics/components/settings/global_params/delete_param.tsx @@ -55,7 +55,7 @@ export const DeleteParam = ({

{' '} {i18n.translate('xpack.synthetics.paramManagement.paramDeleteFailuresMessage.name', { - defaultMessage: 'Param {name} deleted successfully.', + defaultMessage: 'Param {name} failed to delete.', values: { name }, })}

diff --git a/x-pack/plugins/synthetics/public/apps/synthetics/state/global_params/api.ts b/x-pack/plugins/synthetics/public/apps/synthetics/state/global_params/api.ts index 528921f1d5bf4c..1499734639a33e 100644 --- a/x-pack/plugins/synthetics/public/apps/synthetics/state/global_params/api.ts +++ b/x-pack/plugins/synthetics/public/apps/synthetics/state/global_params/api.ts @@ -5,7 +5,7 @@ * 2.0. */ -import { SYNTHETICS_API_URLS } from '../../../../../common/constants'; +import { INITIAL_REST_VERSION, SYNTHETICS_API_URLS } from '../../../../../common/constants'; import { DeleteParamsResponse, SyntheticsParamRequest, @@ -18,7 +18,7 @@ import { apiService } from '../../../../utils/api_service/api_service'; export const getGlobalParams = async (): Promise => { return apiService.get( SYNTHETICS_API_URLS.PARAMS, - undefined, + { version: INITIAL_REST_VERSION }, SyntheticsParamsReadonlyCodec ); }; @@ -26,7 +26,9 @@ export const getGlobalParams = async (): Promise => { export const addGlobalParam = async ( paramRequest: SyntheticsParamRequest ): Promise => - apiService.post(SYNTHETICS_API_URLS.PARAMS, paramRequest, SyntheticsParamsCodec); + apiService.post(SYNTHETICS_API_URLS.PARAMS, paramRequest, SyntheticsParamsCodec, { + version: INITIAL_REST_VERSION, + }); export const editGlobalParam = async ({ paramRequest, @@ -36,15 +38,15 @@ export const editGlobalParam = async ({ paramRequest: SyntheticsParamRequest; }): Promise => apiService.put( - SYNTHETICS_API_URLS.PARAMS, + SYNTHETICS_API_URLS.PARAMS + `/${id}`, + paramRequest, + SyntheticsParamsCodec, { - id, - ...paramRequest, - }, - SyntheticsParamsCodec + version: INITIAL_REST_VERSION, + } ); export const deleteGlobalParams = async (ids: string[]): Promise => - apiService.delete(SYNTHETICS_API_URLS.PARAMS, { - ids: JSON.stringify(ids), + apiService.delete(SYNTHETICS_API_URLS.PARAMS, undefined, { + ids, }); diff --git a/x-pack/plugins/synthetics/public/utils/api_service/api_service.ts b/x-pack/plugins/synthetics/public/utils/api_service/api_service.ts index f1eb2607dd25b9..e077e37d098355 100644 --- a/x-pack/plugins/synthetics/public/utils/api_service/api_service.ts +++ b/x-pack/plugins/synthetics/public/utils/api_service/api_service.ts @@ -101,8 +101,15 @@ class ApiService { return this.parseResponse(response, apiUrl, decodeType); } - public async delete(apiUrl: string, params?: HttpFetchQuery) { - const response = await this._http!.delete({ path: apiUrl, query: params }); + public async delete(apiUrl: string, params: Params = {}, data?: any) { + const { version, ...queryParams } = params; + + const response = await this._http!.delete({ + path: apiUrl, + query: queryParams, + body: JSON.stringify(data), + version, + }); if (response instanceof Error) { throw response; diff --git a/x-pack/plugins/synthetics/server/routes/index.ts b/x-pack/plugins/synthetics/server/routes/index.ts index accad22a12817c..1c02627eddcd77 100644 --- a/x-pack/plugins/synthetics/server/routes/index.ts +++ b/x-pack/plugins/synthetics/server/routes/index.ts @@ -5,6 +5,8 @@ * 2.0. */ +import { getSyntheticsParamsRoute } from './settings/params/params'; +import { editSyntheticsParamsRoute } from './settings/params/edit_param'; import { getConnectorTypesRoute } from './default_alerts/get_connector_types'; import { getActionConnectorsRoute } from './default_alerts/get_action_connectors'; import { SyntheticsRestApiRouteFactory } from './types'; @@ -18,8 +20,6 @@ import { createLastSuccessfulCheckRoute } from './pings/last_successful_check'; import { createJourneyFailedStepsRoute, createJourneyRoute } from './pings/journeys'; import { updateDefaultAlertingRoute } from './default_alerts/update_default_alert'; import { syncParamsSyntheticsParamsRoute } from './settings/sync_global_params'; -import { editSyntheticsParamsRoute } from './settings/edit_param'; -import { getSyntheticsParamsRoute } from './settings/params'; import { getIndexSizesRoute } from './settings/settings'; import { getAPIKeySyntheticsRoute } from './monitor_cruds/get_api_key'; import { getServiceLocationsRoute } from './synthetics_service/get_service_locations'; @@ -44,8 +44,6 @@ import { addSyntheticsProjectMonitorRoute } from './monitor_cruds/add_monitor_pr import { syntheticsGetPingsRoute, syntheticsGetPingStatusesRoute } from './pings'; import { createGetCurrentStatusRoute } from './overview_status/overview_status'; import { getHasIntegrationMonitorsRoute } from './fleet/get_has_integration_monitors'; -import { addSyntheticsParamsRoute } from './settings/add_param'; -import { deleteSyntheticsParamsRoute } from './settings/delete_param'; import { enableDefaultAlertingRoute } from './default_alerts/enable_default_alert'; import { getDefaultAlertingRoute } from './default_alerts/get_default_alert'; import { createNetworkEventsRoute } from './network_events'; @@ -55,6 +53,8 @@ import { getPrivateLocationsRoute } from './settings/private_locations/get_priva import { getSyntheticsFilters } from './filters/filters'; import { getAllSyntheticsMonitorRoute } from './monitor_cruds/get_monitors_list'; import { getLocationMonitors } from './settings/private_locations/get_location_monitors'; +import { addSyntheticsParamsRoute } from './settings/params/add_param'; +import { deleteSyntheticsParamsRoute } from './settings/params/delete_param'; export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ addSyntheticsMonitorRoute, @@ -79,10 +79,6 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ getHasIntegrationMonitorsRoute, createGetCurrentStatusRoute, getIndexSizesRoute, - getSyntheticsParamsRoute, - editSyntheticsParamsRoute, - addSyntheticsParamsRoute, - deleteSyntheticsParamsRoute, syncParamsSyntheticsParamsRoute, enableDefaultAlertingRoute, getDefaultAlertingRoute, @@ -105,3 +101,10 @@ export const syntheticsAppRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ getActionConnectorsRoute, getConnectorTypesRoute, ]; + +export const syntheticsAppPublicRestApiRoutes: SyntheticsRestApiRouteFactory[] = [ + getSyntheticsParamsRoute, + editSyntheticsParamsRoute, + addSyntheticsParamsRoute, + deleteSyntheticsParamsRoute, +]; diff --git a/x-pack/plugins/synthetics/server/routes/settings/add_param.ts b/x-pack/plugins/synthetics/server/routes/settings/add_param.ts deleted file mode 100644 index 875e4da8694e13..00000000000000 --- a/x-pack/plugins/synthetics/server/routes/settings/add_param.ts +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { ALL_SPACES_ID } from '@kbn/security-plugin/common/constants'; -import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; -import { IKibanaResponse } from '@kbn/core/server'; -import { SyntheticsRestApiRouteFactory } from '../types'; -import { - SyntheticsParamRequest, - SyntheticsParams, - SyntheticsParamSOAttributes, -} from '../../../common/runtime_types'; -import { syntheticsParamType } from '../../../common/types/saved_objects'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; - -export const addSyntheticsParamsRoute: SyntheticsRestApiRouteFactory = () => ({ - method: 'POST', - path: SYNTHETICS_API_URLS.PARAMS, - validate: { - body: schema.object({ - key: schema.string(), - value: schema.string(), - description: schema.maybe(schema.string()), - tags: schema.maybe(schema.arrayOf(schema.string())), - share_across_spaces: schema.maybe(schema.boolean()), - }), - }, - writeAccess: true, - handler: async ({ - request, - response, - server, - savedObjectsClient, - }): Promise> => { - try { - const { id: spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { - id: DEFAULT_SPACE_ID, - }; - const { share_across_spaces: shareAcrossSpaces, ...data } = - request.body as SyntheticsParamRequest; - - const { - attributes: { key, tags, description }, - id, - namespaces, - } = await savedObjectsClient.create>( - syntheticsParamType, - data, - { - initialNamespaces: shareAcrossSpaces ? [ALL_SPACES_ID] : [spaceId], - } - ); - return response.ok({ - body: { - id, - description, - key, - namespaces, - tags, - value: data.value, - }, - }); - } catch (error) { - if (error.output?.statusCode === 404) { - const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; - return response.notFound({ - body: { message: `Kibana space '${spaceId}' does not exist` }, - }); - } - - throw error; - } - }, -}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/delete_param.ts b/x-pack/plugins/synthetics/server/routes/settings/delete_param.ts deleted file mode 100644 index dc529902b730f6..00000000000000 --- a/x-pack/plugins/synthetics/server/routes/settings/delete_param.ts +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IKibanaResponse } from '@kbn/core/server'; -import { schema } from '@kbn/config-schema'; -import { SyntheticsRestApiRouteFactory } from '../types'; -import { syntheticsParamType } from '../../../common/types/saved_objects'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; -import { DeleteParamsResponse } from '../../../common/runtime_types'; - -export const deleteSyntheticsParamsRoute: SyntheticsRestApiRouteFactory = () => ({ - method: 'DELETE', - path: SYNTHETICS_API_URLS.PARAMS, - validate: { - query: schema.object({ - ids: schema.string(), - }), - }, - writeAccess: true, - handler: async ({ - savedObjectsClient, - request, - response, - }): Promise> => { - const { ids } = request.query as { ids: string }; - const parsedIds = JSON.parse(ids) as string[]; - - const result = await savedObjectsClient.bulkDelete( - parsedIds.map((id) => ({ type: syntheticsParamType, id })), - { force: true } - ); - return response.ok({ - body: result.statuses.map(({ id, success }) => ({ id, deleted: success })), - }); - }, -}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/edit_param.ts b/x-pack/plugins/synthetics/server/routes/settings/edit_param.ts deleted file mode 100644 index b235d0b323c8b6..00000000000000 --- a/x-pack/plugins/synthetics/server/routes/settings/edit_param.ts +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { schema } from '@kbn/config-schema'; -import { IKibanaResponse, SavedObject } from '@kbn/core/server'; -import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; -import { SyntheticsRestApiRouteFactory } from '../types'; -import { SyntheticsParamRequest, SyntheticsParams } from '../../../common/runtime_types'; -import { syntheticsParamType } from '../../../common/types/saved_objects'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; - -export const editSyntheticsParamsRoute: SyntheticsRestApiRouteFactory = () => ({ - method: 'PUT', - path: SYNTHETICS_API_URLS.PARAMS, - validate: { - body: schema.object({ - id: schema.string(), - key: schema.string(), - value: schema.string(), - description: schema.maybe(schema.string()), - tags: schema.maybe(schema.arrayOf(schema.string())), - share_across_spaces: schema.maybe(schema.boolean()), - }), - }, - writeAccess: true, - handler: async ({ - savedObjectsClient, - request, - response, - server, - }): Promise> => { - try { - const { id: _spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { - id: DEFAULT_SPACE_ID, - }; - const { - share_across_spaces: shareAcrossSpaces, - id, - ...data - } = request.body as SyntheticsParamRequest & { - id: string; - }; - - const { value } = data; - const { - id: responseId, - attributes: { key, tags, description }, - namespaces, - } = (await savedObjectsClient.update( - syntheticsParamType, - id, - data - )) as SavedObject; - - return response.ok({ body: { id: responseId, key, tags, description, namespaces, value } }); - } catch (error) { - if (error.output?.statusCode === 404) { - const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; - return response.notFound({ body: { message: `Kibana space '${spaceId}' does not exist` } }); - } - - throw error; - } - }, -}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/params.ts b/x-pack/plugins/synthetics/server/routes/settings/params.ts deleted file mode 100644 index 789761c529e846..00000000000000 --- a/x-pack/plugins/synthetics/server/routes/settings/params.ts +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one - * or more contributor license agreements. Licensed under the Elastic License - * 2.0; you may not use this file except in compliance with the Elastic License - * 2.0. - */ - -import { IKibanaResponse } from '@kbn/core/server'; -import { SavedObjectsFindResult } from '@kbn/core-saved-objects-api-server'; -import { SyntheticsRestApiRouteFactory } from '../types'; -import { syntheticsParamType } from '../../../common/types/saved_objects'; -import { SYNTHETICS_API_URLS } from '../../../common/constants'; -import { SyntheticsParams, SyntheticsParamsReadonly } from '../../../common/runtime_types'; - -type SyntheticsParamsResponse = - | IKibanaResponse - | IKibanaResponse; -export const getSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< - SyntheticsParamsResponse -> = () => ({ - method: 'GET', - path: SYNTHETICS_API_URLS.PARAMS, - validate: {}, - handler: async ({ savedObjectsClient, request, response, server, spaceId }) => { - try { - const encryptedSavedObjectsClient = server.encryptedSavedObjects.getClient(); - - const canSave = - (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime.save ?? false; - - if (canSave) { - const finder = - await encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( - { - type: syntheticsParamType, - perPage: 1000, - namespaces: [spaceId], - } - ); - - const hits: Array> = []; - for await (const result of finder.find()) { - hits.push(...result.saved_objects); - } - - return response.ok({ - body: hits.map(({ id, attributes, namespaces }) => ({ - ...attributes, - id, - namespaces, - })), - }); - } else { - const data = await savedObjectsClient.find({ - type: syntheticsParamType, - perPage: 10000, - }); - return response.ok({ - body: data.saved_objects.map(({ id, attributes, namespaces }) => ({ - ...attributes, - namespaces, - id, - })), - }); - } - } catch (error) { - if (error.output?.statusCode === 404) { - return response.notFound({ body: { message: `Kibana space '${spaceId}' does not exist` } }); - } - - throw error; - } - }, -}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/add_param.ts b/x-pack/plugins/synthetics/server/routes/settings/params/add_param.ts new file mode 100644 index 00000000000000..9e26666ed30d90 --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/settings/params/add_param.ts @@ -0,0 +1,113 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { ALL_SPACES_ID } from '@kbn/security-plugin/common/constants'; +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { SavedObject, SavedObjectsBulkCreateObject } from '@kbn/core-saved-objects-api-server'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { + SyntheticsParamRequest, + SyntheticsParams, + SyntheticsParamSOAttributes, +} from '../../../../common/runtime_types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; + +const ParamsObjectSchema = schema.object({ + key: schema.string(), + value: schema.string(), + description: schema.maybe(schema.string()), + tags: schema.maybe(schema.arrayOf(schema.string())), + share_across_spaces: schema.maybe(schema.boolean()), +}); + +export const addSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< + SyntheticsParams | SyntheticsParams[] +> = () => ({ + method: 'POST', + path: SYNTHETICS_API_URLS.PARAMS, + validate: {}, + validation: { + request: { + body: schema.oneOf([ParamsObjectSchema, schema.arrayOf(ParamsObjectSchema)]), + }, + }, + writeAccess: true, + handler: async ({ request, response, server, savedObjectsClient }) => { + try { + const { id: spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { + id: DEFAULT_SPACE_ID, + }; + + const savedObjectsData = parseParamBody( + spaceId, + request.body as SyntheticsParamRequest[] | SyntheticsParamRequest + ); + + const result = await savedObjectsClient.bulkCreate>( + savedObjectsData + ); + + if (savedObjectsData.length > 1) { + return result.saved_objects.map((savedObject) => { + return toClientResponse(savedObject); + }); + } else { + return toClientResponse(result.saved_objects[0]); + } + } catch (error) { + if (error.output?.statusCode === 404) { + const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; + return response.notFound({ + body: { message: `Kibana space '${spaceId}' does not exist` }, + }); + } + + throw error; + } + }, +}); + +const toClientResponse = (savedObject: SavedObject>) => { + const { id, attributes: data, namespaces } = savedObject; + const { description, key, tags } = data; + return { + id, + description, + key, + namespaces, + tags, + value: data.value, + }; +}; + +const parseParamBody = ( + spaceId: string, + body: SyntheticsParamRequest[] | SyntheticsParamRequest +): Array>> => { + if (Array.isArray(body)) { + const params = body as SyntheticsParamRequest[]; + return params.map((param) => { + const { share_across_spaces: shareAcrossSpaces, ...data } = param; + return { + type: syntheticsParamType, + attributes: data, + initialNamespaces: shareAcrossSpaces ? [ALL_SPACES_ID] : [spaceId], + }; + }); + } + + const { share_across_spaces: shareAcrossSpaces, ...data } = body; + return [ + { + type: syntheticsParamType, + attributes: data, + initialNamespaces: shareAcrossSpaces ? [ALL_SPACES_ID] : [spaceId], + }, + ]; +}; diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/delete_param.ts b/x-pack/plugins/synthetics/server/routes/settings/params/delete_param.ts new file mode 100644 index 00000000000000..f0f377ce82d9e5 --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/settings/params/delete_param.ts @@ -0,0 +1,40 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; +import { DeleteParamsResponse } from '../../../../common/runtime_types'; + +export const deleteSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< + DeleteParamsResponse[], + unknown, + unknown, + { ids: string[] } +> = () => ({ + method: 'DELETE', + path: SYNTHETICS_API_URLS.PARAMS, + validate: {}, + validation: { + request: { + body: schema.object({ + ids: schema.arrayOf(schema.string()), + }), + }, + }, + writeAccess: true, + handler: async ({ savedObjectsClient, request }) => { + const { ids } = request.body; + + const result = await savedObjectsClient.bulkDelete( + ids.map((id) => ({ type: syntheticsParamType, id })), + { force: true } + ); + return result.statuses.map(({ id, success }) => ({ id, deleted: success })); + }, +}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/edit_param.ts b/x-pack/plugins/synthetics/server/routes/settings/params/edit_param.ts new file mode 100644 index 00000000000000..cd1b0731eedb0d --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/settings/params/edit_param.ts @@ -0,0 +1,76 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema, TypeOf } from '@kbn/config-schema'; +import { SavedObject } from '@kbn/core/server'; +import { DEFAULT_SPACE_ID } from '@kbn/spaces-plugin/common'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { SyntheticsParamRequest, SyntheticsParams } from '../../../../common/runtime_types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; + +const RequestParamsSchema = schema.object({ + id: schema.string(), +}); + +type RequestParams = TypeOf; + +export const editSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< + SyntheticsParams, + RequestParams +> = () => ({ + method: 'PUT', + path: SYNTHETICS_API_URLS.PARAMS + '/{id}', + validate: {}, + validation: { + request: { + params: RequestParamsSchema, + body: schema.object({ + key: schema.string(), + value: schema.string(), + description: schema.maybe(schema.string()), + tags: schema.maybe(schema.arrayOf(schema.string())), + share_across_spaces: schema.maybe(schema.boolean()), + }), + }, + }, + writeAccess: true, + handler: async ({ savedObjectsClient, request, server, response }) => { + try { + const { id: _spaceId } = (await server.spaces?.spacesService.getActiveSpace(request)) ?? { + id: DEFAULT_SPACE_ID, + }; + const { id } = request.params; + const { share_across_spaces: _shareAcrossSpaces, ...data } = + request.body as SyntheticsParamRequest & { + id: string; + }; + + const { value } = data; + const { + id: responseId, + attributes: { key, tags, description }, + namespaces, + } = (await savedObjectsClient.update( + syntheticsParamType, + id, + data + )) as SavedObject; + + return { id: responseId, key, tags, description, namespaces, value }; + } catch (error) { + if (error.output?.statusCode === 404) { + const spaceId = server.spaces?.spacesService.getSpaceId(request) ?? DEFAULT_SPACE_ID; + return response.notFound({ + body: { message: `Kibana space '${spaceId}' does not exist` }, + }); + } + + throw error; + } + }, +}); diff --git a/x-pack/plugins/synthetics/server/routes/settings/params/params.ts b/x-pack/plugins/synthetics/server/routes/settings/params/params.ts new file mode 100644 index 00000000000000..8f9f4f76efd897 --- /dev/null +++ b/x-pack/plugins/synthetics/server/routes/settings/params/params.ts @@ -0,0 +1,102 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { SavedObject, SavedObjectsFindResult } from '@kbn/core-saved-objects-api-server'; +import { schema, TypeOf } from '@kbn/config-schema'; +import { SyntheticsRestApiRouteFactory } from '../../types'; +import { syntheticsParamType } from '../../../../common/types/saved_objects'; +import { SYNTHETICS_API_URLS } from '../../../../common/constants'; +import { SyntheticsParams, SyntheticsParamsReadonly } from '../../../../common/runtime_types'; + +const RequestParamsSchema = schema.object({ + id: schema.maybe(schema.string()), +}); + +type RequestParams = TypeOf; + +export const getSyntheticsParamsRoute: SyntheticsRestApiRouteFactory< + SyntheticsParams[] | SyntheticsParamsReadonly[] | SyntheticsParams | SyntheticsParamsReadonly, + RequestParams +> = () => ({ + method: 'GET', + path: SYNTHETICS_API_URLS.PARAMS + '/{id?}', + validate: {}, + validation: { + request: { + params: RequestParamsSchema, + }, + }, + handler: async ({ savedObjectsClient, request, response, server, spaceId }) => { + try { + const { id: paramId } = request.params; + + const encryptedSavedObjectsClient = server.encryptedSavedObjects.getClient(); + + const canSave = + (await server.coreStart?.capabilities.resolveCapabilities(request)).uptime.save ?? false; + + if (canSave) { + if (paramId) { + const savedObject = + await encryptedSavedObjectsClient.getDecryptedAsInternalUser( + syntheticsParamType, + paramId, + { namespace: spaceId } + ); + return toClientResponse(savedObject); + } + + const finder = + await encryptedSavedObjectsClient.createPointInTimeFinderDecryptedAsInternalUser( + { + type: syntheticsParamType, + perPage: 1000, + namespaces: [spaceId], + } + ); + + const hits: Array> = []; + for await (const result of finder.find()) { + hits.push(...result.saved_objects); + } + + return hits.map((savedObject) => toClientResponse(savedObject)); + } else { + if (paramId) { + const savedObject = await savedObjectsClient.get( + syntheticsParamType, + paramId + ); + return toClientResponse(savedObject); + } + + const data = await savedObjectsClient.find({ + type: syntheticsParamType, + perPage: 10000, + }); + return data.saved_objects.map((savedObject) => toClientResponse(savedObject)); + } + } catch (error) { + if (error.output?.statusCode === 404) { + return response.notFound({ body: { message: `Kibana space '${spaceId}' does not exist` } }); + } + + throw error; + } + }, +}); + +const toClientResponse = ( + savedObject: SavedObject +) => { + const { id, attributes, namespaces } = savedObject; + return { + ...attributes, + id, + namespaces, + }; +}; diff --git a/x-pack/plugins/synthetics/server/routes/types.ts b/x-pack/plugins/synthetics/server/routes/types.ts index b372c6fd11a7f6..7224a6a9e7f5af 100644 --- a/x-pack/plugins/synthetics/server/routes/types.ts +++ b/x-pack/plugins/synthetics/server/routes/types.ts @@ -16,6 +16,7 @@ import { KibanaResponseFactory, IKibanaResponse, } from '@kbn/core/server'; +import { FullValidationConfig } from '@kbn/core-http-server'; import { UptimeEsClient } from '../lib'; import { SyntheticsServerSetup, UptimeRequestHandlerContext } from '../types'; import { SyntheticsMonitorClient } from '../synthetics_service/synthetics_monitor/synthetics_monitor_client'; @@ -32,6 +33,7 @@ export interface UMServerRoute { method: 'GET' | 'PUT' | 'POST' | 'DELETE'; writeAccess?: boolean; handler: T; + validation?: FullValidationConfig; streamHandler?: ( context: UptimeRequestHandlerContext, request: SyntheticsRequest, @@ -57,13 +59,17 @@ export type UMKibanaRoute = UMRouteDefinition< export type SyntheticsRestApiRouteFactory< ClientContract = any, - QueryParams = Record -> = () => SyntheticsRoute; + Params = any, + Query = Record, + Body = any +> = () => SyntheticsRoute; export type SyntheticsRoute< ClientContract = unknown, - QueryParams = Record -> = UMRouteDefinition>; + Params = Record, + Query = Record, + Body = any +> = UMRouteDefinition>; export type SyntheticsRouteWrapper = ( uptimeRoute: SyntheticsRoute>, @@ -81,10 +87,14 @@ export interface UptimeRouteContext { subject?: Subject; } -export interface RouteContext> { +export interface RouteContext< + Params = Record, + Query = Record, + Body = any +> { uptimeEsClient: UptimeEsClient; context: UptimeRequestHandlerContext; - request: KibanaRequest, Query, Record>; + request: KibanaRequest; response: KibanaResponseFactory; savedObjectsClient: SavedObjectsClientContract; server: SyntheticsServerSetup; @@ -93,7 +103,12 @@ export interface RouteContext> { spaceId: string; } -export type SyntheticsRouteHandler> = ({ +export type SyntheticsRouteHandler< + ClientContract, + Params = Record, + Query = Record, + Body = any +> = ({ uptimeEsClient, context, request, @@ -101,4 +116,4 @@ export type SyntheticsRouteHandler) => Promise | ClientContract>; +}: RouteContext) => Promise | ClientContract>; diff --git a/x-pack/plugins/synthetics/server/server.ts b/x-pack/plugins/synthetics/server/server.ts index 9e829045013d4a..69a1aa79d2410e 100644 --- a/x-pack/plugins/synthetics/server/server.ts +++ b/x-pack/plugins/synthetics/server/server.ts @@ -11,7 +11,7 @@ import { SyntheticsPluginsSetupDependencies, SyntheticsServerSetup } from './typ import { createSyntheticsRouteWithAuth } from './routes/create_route_with_auth'; import { SyntheticsMonitorClient } from './synthetics_service/synthetics_monitor/synthetics_monitor_client'; import { syntheticsRouteWrapper } from './synthetics_route_wrapper'; -import { syntheticsAppRestApiRoutes } from './routes'; +import { syntheticsAppPublicRestApiRoutes, syntheticsAppRestApiRoutes } from './routes'; export const initSyntheticsServer = ( server: SyntheticsServerSetup, @@ -19,6 +19,7 @@ export const initSyntheticsServer = ( plugins: SyntheticsPluginsSetupDependencies, ruleDataClient: IRuleDataClient ) => { + const { router } = server; syntheticsAppRestApiRoutes.forEach((route) => { const { method, options, handler, validate, path } = syntheticsRouteWrapper( createSyntheticsRouteWithAuth(route), @@ -34,16 +35,103 @@ export const initSyntheticsServer = ( switch (method) { case 'GET': - server.router.get(routeDefinition, handler); + router.get(routeDefinition, handler); break; case 'POST': - server.router.post(routeDefinition, handler); + router.post(routeDefinition, handler); break; case 'PUT': - server.router.put(routeDefinition, handler); + router.put(routeDefinition, handler); break; case 'DELETE': - server.router.delete(routeDefinition, handler); + router.delete(routeDefinition, handler); + break; + default: + throw new Error(`Handler for method ${method} is not defined`); + } + }); + + syntheticsAppPublicRestApiRoutes.forEach((route) => { + const { method, options, handler, validate, path, validation } = syntheticsRouteWrapper( + createSyntheticsRouteWithAuth(route), + server, + syntheticsMonitorClient + ); + + const routeDefinition = { + path, + validate, + options, + }; + + switch (method) { + case 'GET': + router.versioned + .get({ + access: 'public', + path: routeDefinition.path, + options: { + tags: options?.tags, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: validation ?? false, + }, + handler + ); + break; + case 'PUT': + router.versioned + .put({ + access: 'public', + path: routeDefinition.path, + options: { + tags: options?.tags, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: validation ?? false, + }, + handler + ); + break; + case 'POST': + router.versioned + .post({ + access: 'public', + path: routeDefinition.path, + options: { + tags: options?.tags, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: validation ?? false, + }, + handler + ); + break; + case 'DELETE': + router.versioned + .delete({ + access: 'public', + path: routeDefinition.path, + options: { + tags: options?.tags, + }, + }) + .addVersion( + { + version: '2023-10-31', + validate: validation ?? false, + }, + handler + ); break; default: throw new Error(`Handler for method ${method} is not defined`); diff --git a/x-pack/plugins/uptime/public/legacy_uptime/components/settings/settings_actions.tsx b/x-pack/plugins/uptime/public/legacy_uptime/components/settings/settings_actions.tsx index c7aec1dd90d70b..4e1f1b4c089e17 100644 --- a/x-pack/plugins/uptime/public/legacy_uptime/components/settings/settings_actions.tsx +++ b/x-pack/plugins/uptime/public/legacy_uptime/components/settings/settings_actions.tsx @@ -6,7 +6,7 @@ */ import React from 'react'; -import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiButtonEmpty, EuiText } from '@elastic/eui'; +import { EuiFlexGroup, EuiFlexItem, EuiButton, EuiText } from '@elastic/eui'; import { FormattedMessage } from '@kbn/i18n-react'; import { euiStyled } from '@kbn/kibana-react-plugin/common'; import { SettingsPageFieldErrors } from '../../pages/settings'; @@ -41,8 +41,8 @@ export const SettingsActions = ({ - - + { .send([{ ...getSimpleRule(), investigation_fields: ['foo'] }]) .expect(400); - expect(body.message).to.eql( - '[request body]: Invalid value "["foo"]" supplied to "investigation_fields"' - ); + expect(body.message).to.eql('[request body]: 0: Invalid input'); }); }); }); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts index 2969429494b287..2ce7684dedd486 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/index.ts @@ -21,7 +21,6 @@ export default ({ loadTestFile }: FtrProviderContext): void => { loadTestFile(require.resolve('./create_index')); loadTestFile(require.resolve('./preview_rules')); loadTestFile(require.resolve('./create_rules_bulk')); - loadTestFile(require.resolve('./create_new_terms')); loadTestFile(require.resolve('./delete_rules')); loadTestFile(require.resolve('./delete_rules_bulk')); loadTestFile(require.resolve('./export_rules')); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts index 0babf1dd3535a9..1b2fcee9c71433 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules.ts @@ -719,9 +719,7 @@ export default ({ getService }: FtrProviderContext) => { }) .expect(400); - expect(body.message).to.eql( - '[request body]: Invalid value "["client.foo"]" supplied to "investigation_fields"' - ); + expect(body.message).to.eql('[request body]: Invalid input'); }); it('should patch a rule with a legacy investigation field and transform response', async () => { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts index 28c5a92080c933..4e7010a37dd49b 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/patch_rules_bulk.ts @@ -542,9 +542,7 @@ export default ({ getService }: FtrProviderContext) => { ]) .expect(400); - expect(body.message).to.eql( - '[request body]: Invalid value "["foobar"]" supplied to "investigation_fields"' - ); + expect(body.message).to.eql('[request body]: 0: Invalid input'); }); it('should patch a rule with a legacy investigation field and transform field in response', async () => { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts index c30edde0abea80..7c2d88620924f7 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules.ts @@ -566,7 +566,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body).to.eql({ error: 'Bad Request', - message: '[request body]: Invalid value "undefined" supplied to "threshold"', + message: '[request body]: Invalid input', statusCode: 400, }); }); @@ -615,7 +615,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body).to.eql({ error: 'Bad Request', - message: '[request body]: Invalid value "0" supplied to "threshold,value"', + message: '[request body]: threshold.value: Number must be greater than or equal to 1', statusCode: 400, }); }); @@ -955,9 +955,7 @@ export default ({ getService }: FtrProviderContext) => { .send(updatedRule) .expect(400); - expect(body.message).to.eql( - '[request body]: Invalid value "["foo"]" supplied to "investigation_fields"' - ); + expect(body.message).to.eql('[request body]: Invalid input'); }); it('unsets legacy investigation fields when field not specified for update', async () => { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts index ed87c118bedb97..b5dbf7fca40f26 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/group10/update_rules_bulk.ts @@ -853,9 +853,7 @@ export default ({ getService }: FtrProviderContext) => { ]) .expect(400); - expect(body.message).to.eql( - '[request body]: Invalid value "["client.foo"]" supplied to "investigation_fields"' - ); + expect(body.message).to.eql('[request body]: 0: Invalid input'); }); it('updates a rule with legacy investigation fields and transforms field in response', async () => { diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/prebuilt_rules/fleet_integration.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/prebuilt_rules/fleet_integration.ts index 0683868ae3413b..1433cb7cac2fff 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/prebuilt_rules/fleet_integration.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/prebuilt_rules/fleet_integration.ts @@ -22,8 +22,7 @@ export default ({ getService }: FtrProviderContext): void => { const supertest = getService('supertest'); const log = getService('log'); - // FLAKY: https://github.com/elastic/kibana/issues/167056 - describe.skip('install_prebuilt_rules_from_real_package', () => { + describe('install_prebuilt_rules_from_real_package', () => { beforeEach(async () => { await deletePrebuiltRulesFleetPackage(supertest); await deleteAllRules(supertest, log); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/esql.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/esql.ts index daac0f6c17dddb..9ae0bf9773de6a 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/esql.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/esql.ts @@ -710,7 +710,9 @@ export default ({ getService }: FtrProviderContext) => { expect(previewAlerts.length).toBe(150); }); - it('should generate alerts when docs overlap execution intervals and alerts number reached max_signals in one of the executions', async () => { + // as per https://github.com/elastic/kibana/pull/170034, test is failing on CI and flaky locally + // skipping it for now for further investigation + it.skip('should generate alerts when docs overlap execution intervals and alerts number reached max_signals in one of the executions', async () => { const id = uuidv4(); const rule: EsqlRuleCreateProps = { ...getCreateEsqlRulesSchemaMock('rule-1', true), diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts index 410af1f3f7df3c..69425ac7fa4fc4 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts +++ b/x-pack/test/detection_engine_api_integration/security_and_spaces/rule_execution_logic/query.ts @@ -28,8 +28,8 @@ import { v4 as uuidv4 } from 'uuid'; import { QueryRuleCreateProps, - AlertSuppressionMissingFieldsStrategy, BulkActionType, + AlertSuppressionMissingFieldsStrategyEnum, } from '@kbn/security-solution-plugin/common/api/detection_engine'; import { RuleExecutionStatusEnum } from '@kbn/security-solution-plugin/common/api/detection_engine/rule_monitoring'; import { Ancestor } from '@kbn/security-solution-plugin/server/lib/detection_engine/rule_types/types'; @@ -1478,7 +1478,7 @@ export default ({ getService }: FtrProviderContext) => { query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }, from: 'now-1h', interval: '1h', @@ -1549,7 +1549,7 @@ export default ({ getService }: FtrProviderContext) => { query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }, from: 'now-1h', interval: '1h', @@ -1604,7 +1604,7 @@ export default ({ getService }: FtrProviderContext) => { query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }, from: 'now-1h', interval: '1h', @@ -1658,7 +1658,7 @@ export default ({ getService }: FtrProviderContext) => { query: `id:${id}`, alert_suppression: { group_by: ['agent.name'], - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }, from: 'now-1h', interval: '1h', @@ -1756,7 +1756,7 @@ export default ({ getService }: FtrProviderContext) => { query: `id:${id}`, alert_suppression: { group_by: ['agent.name', 'agent.version'], - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }, from: 'now-1h', interval: '1h', @@ -1835,7 +1835,7 @@ export default ({ getService }: FtrProviderContext) => { query: `id:${id}`, alert_suppression: { group_by: ['agent.name', 'agent.version'], - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }, from: 'now-1h', interval: '1h', @@ -1906,7 +1906,7 @@ export default ({ getService }: FtrProviderContext) => { value: 300, unit: 'm', }, - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.Suppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.suppress, }, from: 'now-1h', interval: '1h', @@ -1973,7 +1973,7 @@ export default ({ getService }: FtrProviderContext) => { value: 300, unit: 'm', }, - missing_fields_strategy: AlertSuppressionMissingFieldsStrategy.DoNotSuppress, + missing_fields_strategy: AlertSuppressionMissingFieldsStrategyEnum.doNotSuppress, }, from: 'now-1h', interval: '1h', diff --git a/x-pack/test/functional/apps/aiops/change_point_detection.ts b/x-pack/test/functional/apps/aiops/change_point_detection.ts index 0cbff0642aa3c0..f643de514c0cb1 100644 --- a/x-pack/test/functional/apps/aiops/change_point_detection.ts +++ b/x-pack/test/functional/apps/aiops/change_point_detection.ts @@ -94,5 +94,13 @@ export default function ({ getPageObjects, getService }: FtrProviderContext) { await aiops.changePointDetectionPage.addChangePointConfig(); await aiops.changePointDetectionPage.assertPanelExist(1); }); + + it('attaches change point charts to a dashboard', async () => { + await aiops.changePointDetectionPage.assertPanelExist(0); + await aiops.changePointDetectionPage.attachChartsToDashboard(0, { + applyTimeRange: true, + maxSeries: 1, + }); + }); }); } diff --git a/x-pack/test/functional/apps/discover/async_scripted_fields.js b/x-pack/test/functional/apps/discover/async_scripted_fields.js index 5810830aec3a61..f3ae63dd427aa8 100644 --- a/x-pack/test/functional/apps/discover/async_scripted_fields.js +++ b/x-pack/test/functional/apps/discover/async_scripted_fields.js @@ -75,13 +75,8 @@ export default function ({ getService, getPageObjects }) { await PageObjects.common.navigateToApp('discover'); await PageObjects.discover.selectIndexPattern('logsta*'); - await retry.tryForTime(20000, async function () { - // wait for shards failed message - const shardMessage = await testSubjects.getVisibleText( - 'dscNoResultsInterceptedWarningsCallout_warningTitle' - ); - log.debug(shardMessage); - expect(shardMessage).to.be('Results are partial and may be incomplete.'); + await retry.try(async function () { + await testSubjects.existOrFail('searchResponseWarningsEmptyPrompt'); }); }); @@ -104,9 +99,8 @@ export default function ({ getService, getPageObjects }) { await dashboardAddPanel.addSavedSearch('search with warning'); await PageObjects.header.waitUntilLoadingHasFinished(); - await retry.tryForTime(20000, async function () { - // wait for shards failed message - await testSubjects.existOrFail('savedSearchEmbeddableWarningsCallout_trigger'); + await retry.try(async function () { + await testSubjects.existOrFail('searchResponseWarningsBadgeToogleButton'); }); }); diff --git a/x-pack/test/functional/apps/infra/hosts_view.ts b/x-pack/test/functional/apps/infra/hosts_view.ts index 10967ae7c2ca83..a7c0ba54298fc9 100644 --- a/x-pack/test/functional/apps/infra/hosts_view.ts +++ b/x-pack/test/functional/apps/infra/hosts_view.ts @@ -358,8 +358,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { }); }); - // FLAKY: https://github.com/elastic/kibana/issues/166344 - describe.skip('Host details page navigation', () => { + describe('Host details page navigation', () => { after(async () => { await pageObjects.common.navigateToApp(HOSTS_VIEW_PATH); await pageObjects.header.waitUntilLoadingHasFinished(); @@ -371,12 +370,14 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => { await waitForPageToLoad(); }); - it('maintains selected date range when navigating to the individual host details', async () => { + it('should maintain the selected date range when navigating to the individual host details', async () => { const start = START_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT); const end = END_HOST_PROCESSES_DATE.format(DATE_PICKER_FORMAT); await pageObjects.timePicker.setAbsoluteRange(start, end); + await waitForPageToLoad(); + const hostDetailLinks = await pageObjects.infraHostsView.getAllHostDetailLinks(); expect(hostDetailLinks.length).not.to.equal(0); diff --git a/x-pack/test/functional/es_archives/canvas/reports/data.json.gz b/x-pack/test/functional/es_archives/canvas/reports/data.json.gz deleted file mode 100644 index 49d7f9093459b8..00000000000000 Binary files a/x-pack/test/functional/es_archives/canvas/reports/data.json.gz and /dev/null differ diff --git a/x-pack/test/functional/es_archives/canvas/reports/mappings.json b/x-pack/test/functional/es_archives/canvas/reports/mappings.json deleted file mode 100644 index d6c3f1b26a4302..00000000000000 --- a/x-pack/test/functional/es_archives/canvas/reports/mappings.json +++ /dev/null @@ -1,2385 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - ".kibana": { - } - }, - "index": ".kibana_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "action": "6e96ac5e648f57523879661ea72525b7", - "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", - "alert": "eaf6f5841dbf4cb5e3045860f75f53ca", - "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", - "apm-telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "app_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "application_usage_daily": "43b8830d5d0df85a6823d290885fc9fd", - "application_usage_totals": "3d1b76c39bfb2cc8296b024d73854724", - "application_usage_transactional": "3d1b76c39bfb2cc8296b024d73854724", - "canvas-element": "7390014e1091044523666d97247392fc", - "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", - "canvas-workpad-template": "ae2673f678281e2c055d764b153e9715", - "cases": "477f214ff61acc3af26a7b7818e380c1", - "cases-comments": "c2061fb929f585df57425102fa928b4b", - "cases-configure": "387c5f3a3bda7e0ae0dd4e106f914a69", - "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", - "config": "c63748b75f39d0c54de12d12c1ccbc20", - "dashboard": "40554caf09725935e2c02e02563a2d07", - "endpoint:user-artifact": "4a11183eee21e6fbad864f7a30b39ad0", - "endpoint:user-artifact-manifest": "a0d7b04ad405eed54d76e279c3727862", - "enterprise_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "epm-packages": "2b83397e3eaaaa8ef15e38813f3721c3", - "exception-list": "67f055ab8c10abd7b2ebfd969b836788", - "exception-list-agnostic": "67f055ab8c10abd7b2ebfd969b836788", - "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", - "fleet-agent-actions": "9511b565b1cc6441a42033db3d5de8e9", - "fleet-agent-events": "e20a508b6e805189356be381dbfac8db", - "fleet-agents": "cb661e8ede2b640c42c8e5ef99db0683", - "fleet-enrollment-api-keys": "a69ef7ae661dab31561d6c6f052ef2a7", - "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", - "index-pattern": "45915a1ad866812242df474eb0479052", - "infrastructure-ui-source": "3d1b76c39bfb2cc8296b024d73854724", - "ingest-agent-policies": "8b0733cce189659593659dad8db426f0", - "ingest-outputs": "8854f34453a47e26f86a29f8f3b80b4e", - "ingest-package-policies": "f74dfe498e1849267cda41580b2be110", - "ingest_manager_settings": "02a03095f0e05b7a538fa801b88a217f", - "inventory-view": "3d1b76c39bfb2cc8296b024d73854724", - "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", - "lens": "52346cfec69ff7b47d5f0c12361a2797", - "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", - "map": "4a05b35c3a3a58fbc72dd0202dc3487f", - "maps-telemetry": "5ef305b18111b77789afefbd36b66171", - "metrics-explorer-view": "3d1b76c39bfb2cc8296b024d73854724", - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", - "monitoring-telemetry": "2669d5ec15e82391cf58df4294ee9c68", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", - "search": "43012c7ebc4cb57054e0a490e4b43023", - "search-telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "siem-detection-engine-rule-actions": "6569b288c169539db10cb262bf79de18", - "siem-detection-engine-rule-status": "ae783f41c6937db6b7a2ef5c93a9e9b0", - "siem-ui-timeline": "d12c5474364d737d17252acf1dc4585c", - "siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084", - "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29", - "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", - "telemetry": "36a616f7026dfa617d6655df850fe16d", - "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", - "type": "2f4316de49999235636386fe51dc06c1", - "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0", - "upgrade-assistant-reindex-operation": "215107c281839ea9b3ad5f6419819763", - "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", - "uptime-dynamic-settings": "3d1b76c39bfb2cc8296b024d73854724", - "url": "c7f66a0df8b1b52f17c28c4adb111105", - "visualization": "f819cf6636b75c9e76ba733a0c6ef355", - "workplace_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724" - } - }, - "dynamic": "strict", - "properties": { - "action": { - "properties": { - "actionTypeId": { - "type": "keyword" - }, - "config": { - "enabled": false, - "type": "object" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "secrets": { - "type": "binary" - } - } - }, - "action_task_params": { - "properties": { - "actionId": { - "type": "keyword" - }, - "apiKey": { - "type": "binary" - }, - "params": { - "enabled": false, - "type": "object" - } - } - }, - "alert": { - "properties": { - "actions": { - "properties": { - "actionRef": { - "type": "keyword" - }, - "actionTypeId": { - "type": "keyword" - }, - "group": { - "type": "keyword" - }, - "params": { - "enabled": false, - "type": "object" - } - }, - "type": "nested" - }, - "alertTypeId": { - "type": "keyword" - }, - "apiKey": { - "type": "binary" - }, - "apiKeyOwner": { - "type": "keyword" - }, - "consumer": { - "type": "keyword" - }, - "createdAt": { - "type": "date" - }, - "createdBy": { - "type": "keyword" - }, - "enabled": { - "type": "boolean" - }, - "executionStatus": { - "properties": { - "error": { - "properties": { - "message": { - "type": "keyword" - }, - "reason": { - "type": "keyword" - } - } - }, - "lastExecutionDate": { - "type": "date" - }, - "status": { - "type": "keyword" - } - } - }, - "meta": { - "properties": { - "versionApiKeyLastmodified": { - "type": "keyword" - } - } - }, - "muteAll": { - "type": "boolean" - }, - "mutedInstanceIds": { - "type": "keyword" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "params": { - "enabled": false, - "type": "object" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledTaskId": { - "type": "keyword" - }, - "tags": { - "type": "keyword" - }, - "throttle": { - "type": "keyword" - }, - "updatedBy": { - "type": "keyword" - } - } - }, - "apm-indices": { - "properties": { - "error": { - "type": "keyword" - }, - "metric": { - "type": "keyword" - }, - "onboarding": { - "type": "keyword" - }, - "sourcemap": { - "type": "keyword" - }, - "span": { - "type": "keyword" - }, - "transaction": { - "type": "keyword" - } - } - }, - "apm-telemetry": { - "dynamic": "false", - "type": "object" - }, - "app_search_telemetry": { - "dynamic": "false", - "type": "object" - }, - "application_usage_daily": { - "dynamic": "false", - "properties": { - "timestamp": { - "type": "date" - } - } - }, - "application_usage_totals": { - "dynamic": "false", - "type": "object" - }, - "application_usage_transactional": { - "dynamic": "false", - "type": "object" - }, - "canvas-element": { - "dynamic": "false", - "properties": { - "@created": { - "type": "date" - }, - "@timestamp": { - "type": "date" - }, - "content": { - "type": "text" - }, - "help": { - "type": "text" - }, - "image": { - "type": "text" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "canvas-workpad": { - "dynamic": "false", - "properties": { - "@created": { - "type": "date" - }, - "@timestamp": { - "type": "date" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "canvas-workpad-template": { - "dynamic": "false", - "properties": { - "help": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "name": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "tags": { - "fields": { - "keyword": { - "type": "keyword" - } - }, - "type": "text" - }, - "template_key": { - "type": "keyword" - } - } - }, - "cases": { - "properties": { - "closed_at": { - "type": "date" - }, - "closed_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "connector": { - "properties": { - "fields": { - "properties": { - "key": { - "type": "text" - }, - "value": { - "type": "text" - } - } - }, - "id": { - "type": "keyword" - }, - "name": { - "type": "text" - }, - "type": { - "type": "keyword" - } - } - }, - "created_at": { - "type": "date" - }, - "created_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "description": { - "type": "text" - }, - "external_service": { - "properties": { - "connector_id": { - "type": "keyword" - }, - "connector_name": { - "type": "keyword" - }, - "external_id": { - "type": "keyword" - }, - "external_title": { - "type": "text" - }, - "external_url": { - "type": "text" - }, - "pushed_at": { - "type": "date" - }, - "pushed_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - } - } - }, - "status": { - "type": "keyword" - }, - "tags": { - "type": "keyword" - }, - "title": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - }, - "updated_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - } - } - }, - "cases-comments": { - "properties": { - "comment": { - "type": "text" - }, - "created_at": { - "type": "date" - }, - "created_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "pushed_at": { - "type": "date" - }, - "pushed_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "updated_at": { - "type": "date" - }, - "updated_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - } - } - }, - "cases-configure": { - "properties": { - "closure_type": { - "type": "keyword" - }, - "connector": { - "properties": { - "fields": { - "properties": { - "key": { - "type": "text" - }, - "value": { - "type": "text" - } - } - }, - "id": { - "type": "keyword" - }, - "name": { - "type": "text" - }, - "type": { - "type": "keyword" - } - } - }, - "created_at": { - "type": "date" - }, - "created_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "updated_at": { - "type": "date" - }, - "updated_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - } - } - }, - "cases-user-actions": { - "properties": { - "action": { - "type": "keyword" - }, - "action_at": { - "type": "date" - }, - "action_by": { - "properties": { - "email": { - "type": "keyword" - }, - "full_name": { - "type": "keyword" - }, - "username": { - "type": "keyword" - } - } - }, - "action_field": { - "type": "keyword" - }, - "new_value": { - "type": "text" - }, - "old_value": { - "type": "text" - } - } - }, - "config": { - "dynamic": "false", - "properties": { - "buildNum": { - "type": "keyword" - } - } - }, - "dashboard": { - "properties": { - "description": { - "type": "text" - }, - "hits": { - "doc_values": false, - "index": false, - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "index": false, - "type": "text" - } - } - }, - "optionsJSON": { - "index": false, - "type": "text" - }, - "panelsJSON": { - "index": false, - "type": "text" - }, - "refreshInterval": { - "properties": { - "display": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "pause": { - "doc_values": false, - "index": false, - "type": "boolean" - }, - "section": { - "doc_values": false, - "index": false, - "type": "integer" - }, - "value": { - "doc_values": false, - "index": false, - "type": "integer" - } - } - }, - "timeFrom": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "timeRestore": { - "doc_values": false, - "index": false, - "type": "boolean" - }, - "timeTo": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "endpoint:user-artifact": { - "properties": { - "body": { - "type": "binary" - }, - "compressionAlgorithm": { - "index": false, - "type": "keyword" - }, - "created": { - "index": false, - "type": "date" - }, - "decodedSha256": { - "index": false, - "type": "keyword" - }, - "decodedSize": { - "index": false, - "type": "long" - }, - "encodedSha256": { - "type": "keyword" - }, - "encodedSize": { - "index": false, - "type": "long" - }, - "encryptionAlgorithm": { - "index": false, - "type": "keyword" - }, - "identifier": { - "type": "keyword" - } - } - }, - "endpoint:user-artifact-manifest": { - "properties": { - "created": { - "index": false, - "type": "date" - }, - "schemaVersion": { - "type": "keyword" - }, - "semanticVersion": { - "index": false, - "type": "keyword" - }, - "artifacts": { - "type": "nested", - "properties": { - "policyId": { - "type": "keyword", - "index": false - }, - "artifactId": { - "type": "keyword", - "index": false - } - } - } - } - }, - "enterprise_search_telemetry": { - "dynamic": "false", - "type": "object" - }, - "epm-packages": { - "properties": { - "es_index_patterns": { - "enabled": false, - "type": "object" - }, - "install_source": { - "type": "keyword" - }, - "install_started_at": { - "type": "date" - }, - "install_status": { - "type": "keyword" - }, - "install_version": { - "type": "keyword" - }, - "installed_es": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "installed_kibana": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "internal": { - "type": "boolean" - }, - "name": { - "type": "keyword" - }, - "removable": { - "type": "boolean" - }, - "version": { - "type": "keyword" - } - } - }, - "exception-list": { - "properties": { - "_tags": { - "type": "keyword" - }, - "comments": { - "properties": { - "comment": { - "type": "keyword" - }, - "created_at": { - "type": "keyword" - }, - "created_by": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "updated_at": { - "type": "keyword" - }, - "updated_by": { - "type": "keyword" - } - } - }, - "created_at": { - "type": "keyword" - }, - "created_by": { - "type": "keyword" - }, - "description": { - "type": "keyword" - }, - "entries": { - "properties": { - "entries": { - "properties": { - "field": { - "type": "keyword" - }, - "operator": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "value": { - "fields": { - "text": { - "type": "text" - } - }, - "type": "keyword" - } - } - }, - "field": { - "type": "keyword" - }, - "list": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "operator": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "value": { - "fields": { - "text": { - "type": "text" - } - }, - "type": "keyword" - } - } - }, - "immutable": { - "type": "boolean" - }, - "item_id": { - "type": "keyword" - }, - "list_id": { - "type": "keyword" - }, - "list_type": { - "type": "keyword" - }, - "meta": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "os_types": { - "type": "keyword" - }, - "tags": { - "type": "keyword" - }, - "tie_breaker_id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "updated_by": { - "type": "keyword" - }, - "version": { - "type": "keyword" - } - } - }, - "exception-list-agnostic": { - "properties": { - "_tags": { - "type": "keyword" - }, - "comments": { - "properties": { - "comment": { - "type": "keyword" - }, - "created_at": { - "type": "keyword" - }, - "created_by": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "updated_at": { - "type": "keyword" - }, - "updated_by": { - "type": "keyword" - } - } - }, - "created_at": { - "type": "keyword" - }, - "created_by": { - "type": "keyword" - }, - "description": { - "type": "keyword" - }, - "entries": { - "properties": { - "entries": { - "properties": { - "field": { - "type": "keyword" - }, - "operator": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "value": { - "fields": { - "text": { - "type": "text" - } - }, - "type": "keyword" - } - } - }, - "field": { - "type": "keyword" - }, - "list": { - "properties": { - "id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "operator": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "value": { - "fields": { - "text": { - "type": "text" - } - }, - "type": "keyword" - } - } - }, - "immutable": { - "type": "boolean" - }, - "item_id": { - "type": "keyword" - }, - "list_id": { - "type": "keyword" - }, - "list_type": { - "type": "keyword" - }, - "meta": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "os_types": { - "type": "keyword" - }, - "tags": { - "type": "keyword" - }, - "tie_breaker_id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "updated_by": { - "type": "keyword" - }, - "version": { - "type": "keyword" - } - } - }, - "file-upload-telemetry": { - "properties": { - "filesUploadedTotalCount": { - "type": "long" - } - } - }, - "fleet-agent-actions": { - "properties": { - "ack_data": { - "type": "text" - }, - "agent_id": { - "type": "keyword" - }, - "created_at": { - "type": "date" - }, - "data": { - "type": "binary" - }, - "policy_id": { - "type": "keyword" - }, - "policy_revision": { - "type": "integer" - }, - "sent_at": { - "type": "date" - }, - "type": { - "type": "keyword" - } - } - }, - "fleet-agent-events": { - "properties": { - "action_id": { - "type": "keyword" - }, - "agent_id": { - "type": "keyword" - }, - "data": { - "type": "text" - }, - "message": { - "type": "text" - }, - "payload": { - "type": "text" - }, - "policy_id": { - "type": "keyword" - }, - "stream_id": { - "type": "keyword" - }, - "subtype": { - "type": "keyword" - }, - "timestamp": { - "type": "date" - }, - "type": { - "type": "keyword" - } - } - }, - "fleet-agents": { - "properties": { - "access_api_key_id": { - "type": "keyword" - }, - "active": { - "type": "boolean" - }, - "current_error_events": { - "index": false, - "type": "text" - }, - "default_api_key": { - "type": "binary" - }, - "default_api_key_id": { - "type": "keyword" - }, - "enrolled_at": { - "type": "date" - }, - "last_checkin": { - "type": "date" - }, - "last_checkin_status": { - "type": "keyword" - }, - "last_updated": { - "type": "date" - }, - "local_metadata": { - "type": "flattened" - }, - "packages": { - "type": "keyword" - }, - "policy_id": { - "type": "keyword" - }, - "policy_revision": { - "type": "integer" - }, - "shared_id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "unenrolled_at": { - "type": "date" - }, - "unenrollment_started_at": { - "type": "date" - }, - "updated_at": { - "type": "date" - }, - "upgrade_started_at": { - "type": "date" - }, - "upgraded_at": { - "type": "date" - }, - "user_provided_metadata": { - "type": "flattened" - }, - "version": { - "type": "keyword" - } - } - }, - "fleet-enrollment-api-keys": { - "properties": { - "active": { - "type": "boolean" - }, - "api_key": { - "type": "binary" - }, - "api_key_id": { - "type": "keyword" - }, - "created_at": { - "type": "date" - }, - "expire_at": { - "type": "date" - }, - "name": { - "type": "keyword" - }, - "policy_id": { - "type": "keyword" - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "graph-workspace": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "type": "text" - } - } - }, - "numLinks": { - "type": "integer" - }, - "numVertices": { - "type": "integer" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - }, - "wsState": { - "type": "text" - } - } - }, - "index-pattern": { - "dynamic": "false", - "properties": { - "title": { - "type": "text" - }, - "type": { - "type": "keyword" - } - } - }, - "infrastructure-ui-source": { - "dynamic": "false", - "type": "object" - }, - "ingest-agent-policies": { - "properties": { - "description": { - "type": "text" - }, - "is_default": { - "type": "boolean" - }, - "monitoring_enabled": { - "index": false, - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "namespace": { - "type": "keyword" - }, - "package_policies": { - "type": "keyword" - }, - "revision": { - "type": "integer" - }, - "status": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - }, - "updated_by": { - "type": "keyword" - } - } - }, - "ingest-outputs": { - "properties": { - "ca_sha256": { - "index": false, - "type": "keyword" - }, - "config": { - "type": "flattened" - }, - "config_yaml": { - "type": "text" - }, - "fleet_enroll_password": { - "type": "binary" - }, - "fleet_enroll_username": { - "type": "binary" - }, - "hosts": { - "type": "keyword" - }, - "is_default": { - "type": "boolean" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "ingest-package-policies": { - "properties": { - "created_at": { - "type": "date" - }, - "created_by": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "enabled": { - "type": "boolean" - }, - "inputs": { - "enabled": false, - "properties": { - "config": { - "type": "flattened" - }, - "enabled": { - "type": "boolean" - }, - "streams": { - "properties": { - "compiled_stream": { - "type": "flattened" - }, - "config": { - "type": "flattened" - }, - "data_stream": { - "properties": { - "dataset": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "enabled": { - "type": "boolean" - }, - "id": { - "type": "keyword" - }, - "vars": { - "type": "flattened" - } - }, - "type": "nested" - }, - "type": { - "type": "keyword" - }, - "vars": { - "type": "flattened" - } - }, - "type": "nested" - }, - "name": { - "type": "keyword" - }, - "namespace": { - "type": "keyword" - }, - "output_id": { - "type": "keyword" - }, - "package": { - "properties": { - "name": { - "type": "keyword" - }, - "title": { - "type": "keyword" - }, - "version": { - "type": "keyword" - } - } - }, - "policy_id": { - "type": "keyword" - }, - "revision": { - "type": "integer" - }, - "updated_at": { - "type": "date" - }, - "updated_by": { - "type": "keyword" - } - } - }, - "ingest_manager_settings": { - "properties": { - "agent_auto_upgrade": { - "type": "keyword" - }, - "has_seen_add_data_notice": { - "index": false, - "type": "boolean" - }, - "kibana_ca_sha256": { - "type": "keyword" - }, - "kibana_urls": { - "type": "keyword" - }, - "package_auto_upgrade": { - "type": "keyword" - } - } - }, - "inventory-view": { - "dynamic": "false", - "type": "object" - }, - "kql-telemetry": { - "properties": { - "optInCount": { - "type": "long" - }, - "optOutCount": { - "type": "long" - } - } - }, - "lens": { - "properties": { - "description": { - "type": "text" - }, - "expression": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "state": { - "type": "flattened" - }, - "title": { - "type": "text" - }, - "visualizationType": { - "type": "keyword" - } - } - }, - "lens-ui-telemetry": { - "properties": { - "count": { - "type": "integer" - }, - "date": { - "type": "date" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - } - }, - "map": { - "properties": { - "description": { - "type": "text" - }, - "layerListJSON": { - "type": "text" - }, - "mapStateJSON": { - "type": "text" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "maps-telemetry": { - "enabled": false, - "type": "object" - }, - "metrics-explorer-view": { - "dynamic": "false", - "type": "object" - }, - "migrationVersion": { - "dynamic": "true", - "properties": { - "canvas-workpad": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "config": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "space": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "ml-telemetry": { - "properties": { - "file_data_visualizer": { - "properties": { - "index_creation_count": { - "type": "long" - } - } - } - } - }, - "monitoring-telemetry": { - "properties": { - "reportedClusterUuids": { - "type": "keyword" - } - } - }, - "namespace": { - "type": "keyword" - }, - "namespaces": { - "type": "keyword" - }, - "originId": { - "type": "keyword" - }, - "query": { - "properties": { - "description": { - "type": "text" - }, - "filters": { - "enabled": false, - "type": "object" - }, - "query": { - "properties": { - "language": { - "type": "keyword" - }, - "query": { - "index": false, - "type": "keyword" - } - } - }, - "timefilter": { - "enabled": false, - "type": "object" - }, - "title": { - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "sample-data-telemetry": { - "properties": { - "installCount": { - "type": "long" - }, - "unInstallCount": { - "type": "long" - } - } - }, - "search": { - "properties": { - "columns": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "description": { - "type": "text" - }, - "hits": { - "doc_values": false, - "index": false, - "type": "integer" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "index": false, - "type": "text" - } - } - }, - "sort": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "title": { - "type": "text" - }, - "version": { - "type": "integer" - } - } - }, - "search-telemetry": { - "dynamic": "false", - "type": "object" - }, - "siem-detection-engine-rule-actions": { - "properties": { - "actions": { - "properties": { - "action_type_id": { - "type": "keyword" - }, - "group": { - "type": "keyword" - }, - "id": { - "type": "keyword" - }, - "params": { - "enabled": false, - "type": "object" - } - } - }, - "alertThrottle": { - "type": "keyword" - }, - "ruleAlertId": { - "type": "keyword" - }, - "ruleThrottle": { - "type": "keyword" - } - } - }, - "siem-detection-engine-rule-status": { - "properties": { - "alertId": { - "type": "keyword" - }, - "bulkCreateTimeDurations": { - "type": "float" - }, - "gap": { - "type": "text" - }, - "lastFailureAt": { - "type": "date" - }, - "lastFailureMessage": { - "type": "text" - }, - "lastLookBackDate": { - "type": "date" - }, - "lastSuccessAt": { - "type": "date" - }, - "lastSuccessMessage": { - "type": "text" - }, - "searchAfterTimeDurations": { - "type": "float" - }, - "status": { - "type": "keyword" - }, - "statusDate": { - "type": "date" - } - } - }, - "siem-ui-timeline": { - "properties": { - "columns": { - "properties": { - "aggregatable": { - "type": "boolean" - }, - "category": { - "type": "keyword" - }, - "columnHeaderType": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "example": { - "type": "text" - }, - "id": { - "type": "keyword" - }, - "indexes": { - "type": "keyword" - }, - "name": { - "type": "text" - }, - "placeholder": { - "type": "text" - }, - "searchable": { - "type": "boolean" - }, - "type": { - "type": "keyword" - } - } - }, - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "dataProviders": { - "properties": { - "and": { - "properties": { - "enabled": { - "type": "boolean" - }, - "excluded": { - "type": "boolean" - }, - "id": { - "type": "keyword" - }, - "kqlQuery": { - "type": "text" - }, - "name": { - "type": "text" - }, - "queryMatch": { - "properties": { - "displayField": { - "type": "text" - }, - "displayValue": { - "type": "text" - }, - "field": { - "type": "text" - }, - "operator": { - "type": "text" - }, - "value": { - "type": "text" - } - } - }, - "type": { - "type": "text" - } - } - }, - "enabled": { - "type": "boolean" - }, - "excluded": { - "type": "boolean" - }, - "id": { - "type": "keyword" - }, - "kqlQuery": { - "type": "text" - }, - "name": { - "type": "text" - }, - "queryMatch": { - "properties": { - "displayField": { - "type": "text" - }, - "displayValue": { - "type": "text" - }, - "field": { - "type": "text" - }, - "operator": { - "type": "text" - }, - "value": { - "type": "text" - } - } - }, - "type": { - "type": "text" - } - } - }, - "dateRange": { - "properties": { - "end": { - "type": "date" - }, - "start": { - "type": "date" - } - } - }, - "description": { - "type": "text" - }, - "eventType": { - "type": "keyword" - }, - "excludedRowRendererIds": { - "type": "text" - }, - "favorite": { - "properties": { - "favoriteDate": { - "type": "date" - }, - "fullName": { - "type": "text" - }, - "keySearch": { - "type": "text" - }, - "userName": { - "type": "text" - } - } - }, - "filters": { - "properties": { - "exists": { - "type": "text" - }, - "match_all": { - "type": "text" - }, - "meta": { - "properties": { - "alias": { - "type": "text" - }, - "controlledBy": { - "type": "text" - }, - "disabled": { - "type": "boolean" - }, - "field": { - "type": "text" - }, - "formattedValue": { - "type": "text" - }, - "index": { - "type": "keyword" - }, - "key": { - "type": "keyword" - }, - "negate": { - "type": "boolean" - }, - "params": { - "type": "text" - }, - "type": { - "type": "keyword" - }, - "value": { - "type": "text" - } - } - }, - "missing": { - "type": "text" - }, - "query": { - "type": "text" - }, - "range": { - "type": "text" - }, - "script": { - "type": "text" - } - } - }, - "indexNames": { - "type": "text" - }, - "kqlMode": { - "type": "keyword" - }, - "kqlQuery": { - "properties": { - "filterQuery": { - "properties": { - "kuery": { - "properties": { - "expression": { - "type": "text" - }, - "kind": { - "type": "keyword" - } - } - }, - "serializedQuery": { - "type": "text" - } - } - } - } - }, - "savedQueryId": { - "type": "keyword" - }, - "sort": { - "properties": { - "columnId": { - "type": "keyword" - }, - "sortDirection": { - "type": "keyword" - } - } - }, - "status": { - "type": "keyword" - }, - "templateTimelineId": { - "type": "text" - }, - "templateTimelineVersion": { - "type": "integer" - }, - "timelineType": { - "type": "keyword" - }, - "title": { - "type": "text" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "siem-ui-timeline-note": { - "properties": { - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "eventId": { - "type": "keyword" - }, - "note": { - "type": "text" - }, - "timelineId": { - "type": "keyword" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "siem-ui-timeline-pinned-event": { - "properties": { - "created": { - "type": "date" - }, - "createdBy": { - "type": "text" - }, - "eventId": { - "type": "keyword" - }, - "timelineId": { - "type": "keyword" - }, - "updated": { - "type": "date" - }, - "updatedBy": { - "type": "text" - } - } - }, - "space": { - "properties": { - "_reserved": { - "type": "boolean" - }, - "color": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "disabledFeatures": { - "type": "keyword" - }, - "imageUrl": { - "index": false, - "type": "text" - }, - "initials": { - "type": "keyword" - }, - "name": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "telemetry": { - "properties": { - "allowChangingOptInStatus": { - "type": "boolean" - }, - "enabled": { - "type": "boolean" - }, - "lastReported": { - "type": "date" - }, - "lastVersionChecked": { - "type": "keyword" - }, - "reportFailureCount": { - "type": "integer" - }, - "reportFailureVersion": { - "type": "keyword" - }, - "sendUsageFrom": { - "type": "keyword" - }, - "userHasSeenNotice": { - "type": "boolean" - } - } - }, - "tsvb-validation-telemetry": { - "properties": { - "failedRequests": { - "type": "long" - } - } - }, - "type": { - "type": "keyword" - }, - "ui-metric": { - "properties": { - "count": { - "type": "integer" - } - } - }, - "updated_at": { - "type": "date" - }, - "upgrade-assistant-reindex-operation": { - "properties": { - "errorMessage": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "indexName": { - "type": "keyword" - }, - "lastCompletedStep": { - "type": "long" - }, - "locked": { - "type": "date" - }, - "newIndexName": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "reindexOptions": { - "properties": { - "openAndClose": { - "type": "boolean" - }, - "queueSettings": { - "properties": { - "queuedAt": { - "type": "long" - }, - "startedAt": { - "type": "long" - } - } - } - } - }, - "reindexTaskId": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "reindexTaskPercComplete": { - "type": "float" - }, - "runningReindexCount": { - "type": "integer" - }, - "status": { - "type": "integer" - } - } - }, - "upgrade-assistant-telemetry": { - "properties": { - "features": { - "properties": { - "deprecation_logging": { - "properties": { - "enabled": { - "null_value": true, - "type": "boolean" - } - } - } - } - }, - "ui_open": { - "properties": { - "cluster": { - "null_value": 0, - "type": "long" - }, - "indices": { - "null_value": 0, - "type": "long" - }, - "overview": { - "null_value": 0, - "type": "long" - } - } - }, - "ui_reindex": { - "properties": { - "close": { - "null_value": 0, - "type": "long" - }, - "open": { - "null_value": 0, - "type": "long" - }, - "start": { - "null_value": 0, - "type": "long" - }, - "stop": { - "null_value": 0, - "type": "long" - } - } - } - } - }, - "uptime-dynamic-settings": { - "dynamic": "false", - "type": "object" - }, - "url": { - "properties": { - "accessCount": { - "type": "long" - }, - "accessDate": { - "type": "date" - }, - "createDate": { - "type": "date" - }, - "url": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "visualization": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "index": false, - "type": "text" - } - } - }, - "savedSearchRefName": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "index": false, - "type": "text" - }, - "version": { - "type": "integer" - }, - "visState": { - "index": false, - "type": "text" - } - } - }, - "workplace_search_telemetry": { - "dynamic": "false", - "type": "object" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} diff --git a/x-pack/test/functional/es_archives/event_log_telemetry/data.json b/x-pack/test/functional/es_archives/event_log_telemetry/data.json deleted file mode 100644 index 55bc3aee1d2721..00000000000000 --- a/x-pack/test/functional/es_archives/event_log_telemetry/data.json +++ /dev/null @@ -1,222 +0,0 @@ -{ - "type": "doc", - "value": { - "id": "task:Alerting-alerting_telemetry", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "8.2.0" - }, - "references": [ - ], - "task": { - "attempts": 0, - "params": "{}", - "retryAt": null, - "runAt": "2020-09-04T11:51:05.197Z", - "scheduledAt": "2020-09-04T11:51:05.197Z", - "startedAt": null, - "state": "{}", - "ownerId": null, - "status": "idle", - "taskType": "alerting_telemetry" - }, - "type": "task", - "updated_at": "2020-09-04T11:51:05.197Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "task:Actions-actions_telemetry", - "index": ".kibana_task_manager_1", - "source": { - "migrationVersion": { - "task": "8.2.0" - }, - "references": [ - ], - "task": { - "attempts": 0, - "params": "{}", - "retryAt": null, - "runAt": "2020-09-04T11:51:05.197Z", - "scheduledAt": "2020-09-04T11:51:05.197Z", - "startedAt": null, - "state": "{}", - "ownerId": null, - "status": "idle", - "taskType": "actions_telemetry" - }, - "type": "task", - "updated_at": "2020-09-04T11:51:05.197Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "X6bLb3UBt6Z_MVvSTfYk", - "index": ".kibana-event-log-8.0.0-000001", - "source": { - "@timestamp": "2020-10-28T15:19:55.933Z", - "ecs": { - "version": "1.5.0" - }, - "event": { - "action": "test", - "duration": 0, - "end": "2020-10-28T15:19:55.933Z", - "provider": "event_log_fixture", - "start": "2020-10-28T15:19:55.933Z" - }, - "kibana": { - "saved_objects": [ - { - "id": "621f2511-5cd1-44fd-95df-e0df83e354d5", - "rel": "primary", - "type": "event_log_test" - } - ], - "server_uuid": "5b2de169-2785-441b-ae8c-186a1936b17d", - "version": "8.0.0" - }, - "message": "test 2020-10-28T15:19:55.913Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "X6bLb3UBt6Z_MVvSTfYk0000", - "index": ".kibana-event-log-8.0.0-000001", - "source": { - "@timestamp": "2020-10-28T15:19:55.933Z", - "ecs": { - "version": "1.5.0" - }, - "event": { - "action": "test legacy", - "duration": 0, - "end": "2020-10-28T15:19:55.933Z", - "provider": "event_log_fixture", - "start": "2020-10-28T15:19:55.933Z" - }, - "kibana": { - "saved_objects": [ - { - "id": "521f2511-5cd1-44fd-95df-e0df83e354d5", - "rel": "primary", - "type": "event_log_test" - } - ], - "server_uuid": "5b2de169-2785-441b-ae8c-186a1936b17d", - "version": "7.14.0" - }, - "message": "test legacy 2020-10-28T15:19:55.913Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "YKbLb3UBt6Z_MVvSTfY8", - "index": ".kibana-event-log-8.0.0-000001", - "source": { - "@timestamp": "2020-10-28T15:19:55.957Z", - "ecs": { - "version": "1.5.0" - }, - "event": { - "action": "test", - "duration": 0, - "end": "2020-10-28T15:19:55.957Z", - "provider": "event_log_fixture", - "start": "2020-10-28T15:19:55.957Z" - }, - "kibana": { - "saved_objects": [ - { - "id": "621f2511-5cd1-44fd-95df-e0df83e354d5", - "rel": "primary", - "type": "event_log_test" - } - ], - "server_uuid": "5b2de169-2785-441b-ae8c-186a1936b17d", - "version": "8.0.0" - }, - "message": "test 2020-10-28T15:19:55.938Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "YabLb3UBt6Z_MVvSTfZc0000", - "index": ".kibana-event-log-8.0.0-000001", - "source": { - "@timestamp": "2020-10-28T15:19:55.991Z", - "ecs": { - "version": "1.5.0" - }, - "event": { - "action": "test", - "duration": 0, - "end": "2020-10-28T15:19:55.991Z", - "provider": "event_log_fixture", - "start": "2020-10-28T15:19:55.991Z" - }, - "kibana": { - "saved_objects": [ - { - "id": "521f2511-5cd1-44fd-95df-e0df83e354d5", - "rel": "primary", - "type": "event_log_test" - } - ], - "server_uuid": "5b2de169-2785-441b-ae8c-186a1936b17d", - "version": "7.0.0" - }, - "message": "test legacy 2020-10-28T15:19:55.962Z" - } - } -} - -{ - "type": "doc", - "value": { - "id": "YabLb3UBt6Z_MVvSTfZc", - "index": ".kibana-event-log-8.0.0-000001", - "source": { - "@timestamp": "2020-10-28T15:19:55.991Z", - "ecs": { - "version": "1.5.0" - }, - "event": { - "action": "test", - "duration": 0, - "end": "2020-10-28T15:19:55.991Z", - "provider": "event_log_fixture", - "start": "2020-10-28T15:19:55.991Z" - }, - "kibana": { - "saved_objects": [ - { - "id": "621f2511-5cd1-44fd-95df-e0df83e354d5", - "rel": "primary", - "type": "event_log_test" - } - ], - "server_uuid": "5b2de169-2785-441b-ae8c-186a1936b17d", - "version": "8.0.0" - }, - "message": "test 2020-10-28T15:19:55.962Z" - } - } -} \ No newline at end of file diff --git a/x-pack/test/functional/es_archives/event_log_telemetry/mappings.json b/x-pack/test/functional/es_archives/event_log_telemetry/mappings.json deleted file mode 100644 index e833188e6264f0..00000000000000 --- a/x-pack/test/functional/es_archives/event_log_telemetry/mappings.json +++ /dev/null @@ -1,700 +0,0 @@ -{ - "type": "index", - "value": { - "aliases": { - ".kibana": { - } - }, - "index": ".kibana_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "action": "6e96ac5e648f57523879661ea72525b7", - "action_task_params": "a9d49f184ee89641044be0ca2950fa3a", - "alert": "eaf6f5841dbf4cb5e3045860f75f53ca", - "apm-indices": "9bb9b2bf1fa636ed8619cbab5ce6a1dd", - "apm-telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "app_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "application_usage_daily": "43b8830d5d0df85a6823d290885fc9fd", - "application_usage_totals": "3d1b76c39bfb2cc8296b024d73854724", - "application_usage_transactional": "3d1b76c39bfb2cc8296b024d73854724", - "canvas-element": "7390014e1091044523666d97247392fc", - "canvas-workpad": "b0a1706d356228dbdcb4a17e6b9eb231", - "canvas-workpad-template": "ae2673f678281e2c055d764b153e9715", - "cases": "477f214ff61acc3af26a7b7818e380c1", - "cases-comments": "c2061fb929f585df57425102fa928b4b", - "cases-configure": "387c5f3a3bda7e0ae0dd4e106f914a69", - "cases-user-actions": "32277330ec6b721abe3b846cfd939a71", - "config": "c63748b75f39d0c54de12d12c1ccbc20", - "dashboard": "40554caf09725935e2c02e02563a2d07", - "endpoint:user-artifact": "4a11183eee21e6fbad864f7a30b39ad0", - "endpoint:user-artifact-manifest": "a0d7b04ad405eed54d76e279c3727862", - "enterprise_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "epm-packages": "2b83397e3eaaaa8ef15e38813f3721c3", - "event_log_test": "bef808d4a9c27f204ffbda3359233931", - "exception-list": "67f055ab8c10abd7b2ebfd969b836788", - "exception-list-agnostic": "67f055ab8c10abd7b2ebfd969b836788", - "file-upload-telemetry": "0ed4d3e1983d1217a30982630897092e", - "fleet-agent-actions": "9511b565b1cc6441a42033db3d5de8e9", - "fleet-agent-events": "e20a508b6e805189356be381dbfac8db", - "fleet-agents": "cb661e8ede2b640c42c8e5ef99db0683", - "fleet-enrollment-api-keys": "a69ef7ae661dab31561d6c6f052ef2a7", - "graph-workspace": "cd7ba1330e6682e9cc00b78850874be1", - "index-pattern": "45915a1ad866812242df474eb0479052", - "infrastructure-ui-source": "3d1b76c39bfb2cc8296b024d73854724", - "ingest-agent-policies": "8b0733cce189659593659dad8db426f0", - "ingest-outputs": "8854f34453a47e26f86a29f8f3b80b4e", - "ingest-package-policies": "f74dfe498e1849267cda41580b2be110", - "ingest_manager_settings": "02a03095f0e05b7a538fa801b88a217f", - "inventory-view": "3d1b76c39bfb2cc8296b024d73854724", - "kql-telemetry": "d12a98a6f19a2d273696597547e064ee", - "lens": "52346cfec69ff7b47d5f0c12361a2797", - "lens-ui-telemetry": "509bfa5978586998e05f9e303c07a327", - "map": "4a05b35c3a3a58fbc72dd0202dc3487f", - "maps-telemetry": "5ef305b18111b77789afefbd36b66171", - "metrics-explorer-view": "3d1b76c39bfb2cc8296b024d73854724", - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "ml-telemetry": "257fd1d4b4fdbb9cb4b8a3b27da201e9", - "monitoring-telemetry": "2669d5ec15e82391cf58df4294ee9c68", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "originId": "2f4316de49999235636386fe51dc06c1", - "query": "11aaeb7f5f7fa5bb43f25e18ce26e7d9", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "sample-data-telemetry": "7d3cfeb915303c9641c59681967ffeb4", - "search": "43012c7ebc4cb57054e0a490e4b43023", - "search-telemetry": "3d1b76c39bfb2cc8296b024d73854724", - "siem-detection-engine-rule-actions": "6569b288c169539db10cb262bf79de18", - "siem-detection-engine-rule-status": "ae783f41c6937db6b7a2ef5c93a9e9b0", - "siem-ui-timeline": "d12c5474364d737d17252acf1dc4585c", - "siem-ui-timeline-note": "8874706eedc49059d4cf0f5094559084", - "siem-ui-timeline-pinned-event": "20638091112f0e14f0e443d512301c29", - "space": "c5ca8acafa0beaa4d08d014a97b6bc6b", - "telemetry": "36a616f7026dfa617d6655df850fe16d", - "timelion-sheet": "9a2a2748877c7a7b582fef201ab1d4cf", - "tsvb-validation-telemetry": "3a37ef6c8700ae6fc97d5c7da00e9215", - "type": "2f4316de49999235636386fe51dc06c1", - "ui-metric": "0d409297dc5ebe1e3a1da691c6ee32e3", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0", - "upgrade-assistant-reindex-operation": "215107c281839ea9b3ad5f6419819763", - "upgrade-assistant-telemetry": "56702cec857e0a9dacfb696655b4ff7b", - "uptime-dynamic-settings": "3d1b76c39bfb2cc8296b024d73854724", - "url": "c7f66a0df8b1b52f17c28c4adb111105", - "visualization": "f819cf6636b75c9e76ba733a0c6ef355", - "workplace_search_telemetry": "3d1b76c39bfb2cc8296b024d73854724" - } - }, - "dynamic": "strict", - "properties": { - "config": { - "dynamic": "false", - "properties": { - "buildNum": { - "type": "keyword" - } - } - }, - "event_log_test": { - "type": "object" - }, - "migrationVersion": { - "dynamic": "true", - "properties": { - "config": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - }, - "space": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "ml-telemetry": { - "properties": { - "file_data_visualizer": { - "properties": { - "index_creation_count": { - "type": "long" - } - } - } - } - }, - "monitoring-telemetry": { - "properties": { - "reportedClusterUuids": { - "type": "keyword" - } - } - }, - "namespace": { - "type": "keyword" - }, - "namespaces": { - "type": "keyword" - }, - "originId": { - "type": "keyword" - }, - "query": { - "properties": { - "description": { - "type": "text" - }, - "filters": { - "enabled": false, - "type": "object" - }, - "query": { - "properties": { - "language": { - "type": "keyword" - }, - "query": { - "index": false, - "type": "keyword" - } - } - }, - "timefilter": { - "enabled": false, - "type": "object" - }, - "title": { - "type": "text" - } - } - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "type": { - "type": "keyword" - }, - "space": { - "properties": { - "_reserved": { - "type": "boolean" - }, - "color": { - "type": "keyword" - }, - "description": { - "type": "text" - }, - "disabledFeatures": { - "type": "keyword" - }, - "imageUrl": { - "index": false, - "type": "text" - }, - "initials": { - "type": "keyword" - }, - "name": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "ui-metric": { - "properties": { - "count": { - "type": "integer" - } - } - }, - "updated_at": { - "type": "date" - }, - "url": { - "properties": { - "accessCount": { - "type": "long" - }, - "accessDate": { - "type": "date" - }, - "createDate": { - "type": "date" - }, - "url": { - "fields": { - "keyword": { - "ignore_above": 2048, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "visualization": { - "properties": { - "description": { - "type": "text" - }, - "kibanaSavedObjectMeta": { - "properties": { - "searchSourceJSON": { - "index": false, - "type": "text" - } - } - }, - "savedSearchRefName": { - "doc_values": false, - "index": false, - "type": "keyword" - }, - "title": { - "type": "text" - }, - "uiStateJSON": { - "index": false, - "type": "text" - }, - "version": { - "type": "integer" - }, - "visState": { - "index": false, - "type": "text" - } - } - }, - "workplace_search_telemetry": { - "dynamic": "false", - "type": "object" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - ".kibana-event-log-7.9.0": { - "is_write_index": true - } - }, - "index": ".kibana-event-log-7.9.0-000001", - "mappings": { - "dynamic": "false", - "properties": { - "@timestamp": { - "type": "date" - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "error": { - "properties": { - "message": { - "norms": false, - "type": "text" - } - } - }, - "event": { - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "duration": { - "type": "long" - }, - "end": { - "type": "date" - }, - "outcome": { - "ignore_above": 1024, - "type": "keyword" - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "start": { - "type": "date" - } - } - }, - "kibana": { - "properties": { - "alerting": { - "properties": { - "instance_id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "saved_objects": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "namespace": { - "ignore_above": 1024, - "type": "keyword" - }, - "rel": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - }, - "type": "nested" - }, - "server_uuid": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "tags": { - "ignore_above": 1024, - "meta": { - "isArray": "true" - }, - "type": "keyword" - }, - "user": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "lifecycle": { - "name": "kibana-event-log-policy", - "rollover_alias": ".kibana-event-log-7.9.0" - }, - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - ".kibana-event-log-8.0.0": { - "is_write_index": true - } - }, - "index": ".kibana-event-log-8.0.0-000001", - "mappings": { - "dynamic": "false", - "properties": { - "@timestamp": { - "type": "date" - }, - "ecs": { - "properties": { - "version": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "error": { - "properties": { - "message": { - "norms": false, - "type": "text" - } - } - }, - "event": { - "properties": { - "action": { - "ignore_above": 1024, - "type": "keyword" - }, - "duration": { - "type": "long" - }, - "end": { - "type": "date" - }, - "outcome": { - "ignore_above": 1024, - "type": "keyword" - }, - "provider": { - "ignore_above": 1024, - "type": "keyword" - }, - "start": { - "type": "date" - } - } - }, - "kibana": { - "properties": { - "alerting": { - "properties": { - "instance_id": { - "ignore_above": 1024, - "type": "keyword" - } - } - }, - "saved_objects": { - "properties": { - "id": { - "ignore_above": 1024, - "type": "keyword" - }, - "namespace": { - "ignore_above": 1024, - "type": "keyword" - }, - "rel": { - "ignore_above": 1024, - "type": "keyword" - }, - "type": { - "ignore_above": 1024, - "type": "keyword" - } - }, - "type": "nested" - }, - "server_uuid": { - "ignore_above": 1024, - "type": "keyword" - }, - "version": { - "type": "version" - } - } - }, - "message": { - "norms": false, - "type": "text" - }, - "tags": { - "ignore_above": 1024, - "meta": { - "isArray": "true" - }, - "type": "keyword" - }, - "user": { - "properties": { - "name": { - "fields": { - "text": { - "norms": false, - "type": "text" - } - }, - "ignore_above": 1024, - "type": "keyword" - } - } - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "lifecycle": { - "name": "kibana-event-log-policy", - "rollover_alias": ".kibana-event-log-8.0.0" - }, - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} - -{ - "type": "index", - "value": { - "aliases": { - ".kibana_task_manager": { - } - }, - "index": ".kibana_task_manager_1", - "mappings": { - "_meta": { - "migrationMappingPropertyHashes": { - "migrationVersion": "4a1746014a75ade3a714e1db5763276f", - "namespace": "2f4316de49999235636386fe51dc06c1", - "namespaces": "2f4316de49999235636386fe51dc06c1", - "references": "7997cf5a56cc02bdc9c93361bde732b0", - "task": "235412e52d09e7165fac8a67a43ad6b4", - "type": "2f4316de49999235636386fe51dc06c1", - "updated_at": "00da57df13e94e9d98437d13ace4bfe0" - } - }, - "dynamic": "strict", - "properties": { - "migrationVersion": { - "dynamic": "true", - "properties": { - "task": { - "fields": { - "keyword": { - "ignore_above": 256, - "type": "keyword" - } - }, - "type": "text" - } - } - }, - "namespace": { - "type": "keyword" - }, - "namespaces": { - "type": "keyword" - }, - "references": { - "properties": { - "id": { - "type": "keyword" - }, - "name": { - "type": "keyword" - }, - "type": { - "type": "keyword" - } - }, - "type": "nested" - }, - "task": { - "properties": { - "attempts": { - "type": "integer" - }, - "ownerId": { - "type": "keyword" - }, - "params": { - "type": "text" - }, - "retryAt": { - "type": "date" - }, - "runAt": { - "type": "date" - }, - "schedule": { - "properties": { - "interval": { - "type": "keyword" - } - } - }, - "scheduledAt": { - "type": "date" - }, - "scope": { - "type": "keyword" - }, - "startedAt": { - "type": "date" - }, - "state": { - "type": "text" - }, - "status": { - "type": "keyword" - }, - "taskType": { - "type": "keyword" - }, - "user": { - "type": "keyword" - } - } - }, - "type": { - "type": "keyword" - }, - "updated_at": { - "type": "date" - } - } - }, - "settings": { - "index": { - "auto_expand_replicas": "0-1", - "number_of_replicas": "0", - "number_of_shards": "1" - } - } - } -} diff --git a/x-pack/test/functional/services/aiops/change_point_detection_page.ts b/x-pack/test/functional/services/aiops/change_point_detection_page.ts index 2eb539ef4fc784..4f83137df472e4 100644 --- a/x-pack/test/functional/services/aiops/change_point_detection_page.ts +++ b/x-pack/test/functional/services/aiops/change_point_detection_page.ts @@ -9,6 +9,11 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../ftr_provider_context'; import { MlTableService } from '../ml/common_table_service'; +export interface DashboardAttachmentOptions { + applyTimeRange: boolean; + maxSeries: number; +} + export function ChangePointDetectionPageProvider( { getService, getPageObject }: FtrProviderContext, tableService: MlTableService @@ -18,6 +23,7 @@ export function ChangePointDetectionPageProvider( const comboBox = getService('comboBox'); const browser = getService('browser'); const elasticChart = getService('elasticChart'); + const dashboardPage = getPageObject('dashboard'); return { async navigateToIndexPatternSelection() { @@ -124,6 +130,128 @@ export function ChangePointDetectionPageProvider( }); }, + async openPanelContextMenu(panelIndex: number) { + await testSubjects.click( + `aiopsChangePointPanel_${panelIndex} > aiopsChangePointDetectionContextMenuButton` + ); + await retry.tryForTime(30 * 1000, async () => { + await testSubjects.existOrFail(`aiopsChangePointDetectionAttachButton`); + }); + }, + + async clickAttachChartsButton() { + await testSubjects.click('aiopsChangePointDetectionAttachButton'); + await retry.tryForTime(30 * 1000, async () => { + await testSubjects.missingOrFail(`aiopsChangePointDetectionAttachButton`); + await testSubjects.existOrFail(`aiopsChangePointDetectionAttachToDashboardButton`); + }); + }, + + async clickAttachDashboardButton() { + await testSubjects.click('aiopsChangePointDetectionAttachToDashboardButton'); + await retry.tryForTime(30 * 1000, async () => { + await testSubjects.existOrFail(`aiopsChangePointDetectionDashboardAttachmentForm`); + }); + }, + + async assertApplyTimeRangeControl(expectedValue: boolean) { + const isChecked = await testSubjects.isEuiSwitchChecked( + `aiopsChangePointDetectionAttachToDashboardApplyTimeRangeSwitch` + ); + expect(isChecked).to.eql( + expectedValue, + `Expected apply time range to be ${expectedValue ? 'enabled' : 'disabled'}` + ); + }, + + async assertMaxSeriesControl(expectedValue: number) { + const currentValue = Number( + await testSubjects.getAttribute('aiopsMaxSeriesControlFieldNumber', 'value') + ); + expect(currentValue).to.eql( + expectedValue, + `Expected max series control to be ${expectedValue} (got ${currentValue})` + ); + }, + + async toggleApplyTimeRangeControl(isChecked: boolean) { + await testSubjects.setEuiSwitch( + `aiopsChangePointDetectionAttachToDashboardApplyTimeRangeSwitch`, + isChecked ? 'check' : 'uncheck' + ); + await this.assertApplyTimeRangeControl(isChecked); + }, + + async setMaxSeriesControl(value: number) { + await testSubjects.setValue('aiopsMaxSeriesControlFieldNumber', value.toString()); + await this.assertMaxSeriesControl(value); + }, + + async completeDashboardAttachmentForm(attachmentOptions: DashboardAttachmentOptions) { + // assert default values + await this.assertApplyTimeRangeControl(false); + await this.assertMaxSeriesControl(6); + + if (attachmentOptions.applyTimeRange) { + await this.toggleApplyTimeRangeControl(attachmentOptions.applyTimeRange); + } + + if (attachmentOptions.maxSeries) { + await this.setMaxSeriesControl(attachmentOptions.maxSeries); + } + + await testSubjects.click('aiopsChangePointDetectionSubmitDashboardAttachButton'); + + await retry.tryForTime(30 * 1000, async () => { + // await testSubjects.missingOrFail(`aiopsChangePointDetectionSubmitDashboardAttachButton`); + await testSubjects.existOrFail('savedObjectSaveModal'); + }); + }, + + async completeSaveToDashboardForm(options?: { createNew: boolean; dashboardName?: string }) { + await retry.tryForTime(30 * 1000, async () => { + const dashboardSelector = await testSubjects.find('add-to-dashboard-options'); + + if (options?.createNew) { + const label = await dashboardSelector.findByCssSelector( + `label[for="new-dashboard-option"]` + ); + await label.click(); + } + + await testSubjects.click('confirmSaveSavedObjectButton'); + await retry.waitForWithTimeout('Save modal to disappear', 1000, () => + testSubjects + .missingOrFail('confirmSaveSavedObjectButton') + .then(() => true) + .catch(() => false) + ); + + // make sure the dashboard page actually loaded + const dashboardItemCount = await dashboardPage.getSharedItemsCount(); + expect(dashboardItemCount).to.not.eql(undefined); + }); + // changing to the dashboard app might take some time + const embeddable = await testSubjects.find('aiopsEmbeddableChangePointChart', 30 * 1000); + const lensChart = await embeddable.findByClassName('lnsExpressionRenderer'); + expect(await lensChart.isDisplayed()).to.eql( + true, + 'Change point detection chart should be displayed in dashboard' + ); + }, + + async attachChartsToDashboard( + panelIndex: number, + attachmentOptions: DashboardAttachmentOptions + ) { + await this.assertPanelExist(panelIndex); + await this.openPanelContextMenu(panelIndex); + await this.clickAttachChartsButton(); + await this.clickAttachDashboardButton(); + await this.completeDashboardAttachmentForm(attachmentOptions); + await this.completeSaveToDashboardForm({ createNew: true }); + }, + getTable(index: number) { return tableService.getServiceInstance( 'ChangePointResultsTable', diff --git a/x-pack/test/reporting_functional/reporting_and_deprecated_security/security_roles_privileges.ts b/x-pack/test/reporting_functional/reporting_and_deprecated_security/security_roles_privileges.ts index bd13e65ed8a258..f9b84469c1eeeb 100644 --- a/x-pack/test/reporting_functional/reporting_and_deprecated_security/security_roles_privileges.ts +++ b/x-pack/test/reporting_functional/reporting_and_deprecated_security/security_roles_privileges.ts @@ -67,14 +67,17 @@ export default function ({ getService }: FtrProviderContext) { }); describe('Canvas: Generate PDF', () => { - const esArchiver = getService('esArchiver'); const reportingApi = getService('reportingAPI'); + const kibanaServer = getService('kibanaServer'); + before('initialize tests', async () => { - await esArchiver.load('x-pack/test/functional/es_archives/canvas/reports'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/canvas/workpad_pdf_test' + ); }); after('teardown tests', async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/canvas/reports'); + await kibanaServer.savedObjects.cleanStandardList(); await reportingApi.deleteAllReports(); await reportingFunctional.initEcommerce(); }); diff --git a/x-pack/test/reporting_functional/reporting_and_security/security_roles_privileges.ts b/x-pack/test/reporting_functional/reporting_and_security/security_roles_privileges.ts index c2146e8c9dc5fe..16ecce357c56bc 100644 --- a/x-pack/test/reporting_functional/reporting_and_security/security_roles_privileges.ts +++ b/x-pack/test/reporting_functional/reporting_and_security/security_roles_privileges.ts @@ -73,14 +73,16 @@ export default function ({ getService }: FtrProviderContext) { }); describe('Canvas: Generate PDF', () => { - const esArchiver = getService('esArchiver'); + const kibanaServer = getService('kibanaServer'); const reportingApi = getService('reportingAPI'); before('initialize tests', async () => { - await esArchiver.load('x-pack/test/functional/es_archives/canvas/reports'); + await kibanaServer.importExport.load( + 'test/functional/fixtures/kbn_archiver/canvas/workpad_pdf_test' + ); }); after('teardown tests', async () => { - await esArchiver.unload('x-pack/test/functional/es_archives/canvas/reports'); + await kibanaServer.savedObjects.cleanStandardList(); await reportingApi.deleteAllReports(); await reportingFunctional.initEcommerce(); }); diff --git a/x-pack/test/security_solution_api_integration/README.md b/x-pack/test/security_solution_api_integration/README.md index 5995b41164aec0..ebdf649e1e2bb2 100644 --- a/x-pack/test/security_solution_api_integration/README.md +++ b/x-pack/test/security_solution_api_integration/README.md @@ -40,7 +40,53 @@ ex: In the `package.json` file, you'll find commands to configure the server for each environment and to run tests against that specific environment. These commands adhere to the Mocha tagging system, allowing for the inclusion and exclusion of tags, mirroring the setup of the CI pipeline. +## Running Commands with Different Parameters +In this project, you can run various commands to execute tests and workflows, each of which can be customized by specifying different parameters. Below, how to define the commands based on the parameters and their order. +### Command Structure +The command structure follows this pattern: +- ``: The name of the specific command or test case. +- ``: The test folder or workflow you want to run. +- ``: The type of operation, either "server" or "runner." +- ``: The testing environment, such as "serverlessEnv," "essEnv," or "qaEnv." +- ``: The license folder the test is defined under such as "default_license", by default the value is "default_license" +- ``: The area the test is defined under, such as "detection_engine", by default the value is "detection_engine" + +### Serverless and Ess Configuration + +- When using "serverless" or "ess" in the script, it specifies the correct configuration file for the tests. +- "Serverless" and "ess" help determine the configuration specific to the chosen test. + +### serverlessEnv, essEnv, qaEnv Grep Command + +- When using "serverlessEnv,.." in the script, it appends the correct grep command for filtering tests in the serverless testing environment. +- "serverlessEnv,..." is used to customize the test execution based on the serverless environment. + + +### Command Examples + +Here are some command examples using the provided parameters: + +1. **Run the server for "exception_workflows" in the "serverlessEnv" environment:** + ```shell + npm run initialize-server exceptions/workflows serverless + ``` +2. **To run tests for the "exception_workflows" using the serverless runner in the "serverlessEnv" environment, you can use the following command:** + ```shell + npm run run-tests exceptions/workflows serverless serverlessEnv + ``` +3. **Run tests for "exception_workflows" using the serverless runner in the "qaEnv" environment:** + ```shell + npm run run-tests exceptions/workflows serverless qaEnv + ``` +4. **Run the server for "exception_workflows" in the "essEnv" environment:** + ```shell + npm run initialize-server exceptions/workflows ess + ``` +5. **Run tests for "exception_workflows" using the ess runner in the "essEnv" environment:** + ```shell + npm run run-tests exceptions/workflows ess essEnv + ``` \ No newline at end of file diff --git a/x-pack/test/security_solution_api_integration/package.json b/x-pack/test/security_solution_api_integration/package.json index d362078fc03b16..4562cfc82cfc93 100644 --- a/x-pack/test/security_solution_api_integration/package.json +++ b/x-pack/test/security_solution_api_integration/package.json @@ -5,30 +5,32 @@ "private": true, "license": "Elastic License 2.0", "scripts": { - "exception_workflows:server:serverless": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/exceptions/workflows/configs/serverless.config.ts", - "exception_workflows:runner:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/workflows/configs/serverless.config.ts --grep @serverless --grep @brokenInServerless --invert", - "exception_workflows:qa:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/workflows/configs/serverless.config.ts --grep @serverless --grep '@brokenInServerless|@skipInQA' --invert", - "exception_workflows:server:ess": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/exceptions/workflows/configs/ess.config.ts", - "exception_workflows:runner:ess": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/workflows/configs/ess.config.ts --grep @ess", - "exception_operators_date_numeric_types:server:serverless": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/configs/serverless.config.ts", - "exception_operators_date_numeric_types:runner:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/configs/serverless.config.ts --grep @serverless --grep @brokenInServerless --invert", - "exception_operators_date_numeric_types:qa:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/configs/serverless.config.ts --grep @serverless --grep '@brokenInServerless|@skipInQA' --invert", - "exception_operators_date_numeric_types:server:ess": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/configs/ess.config.ts", - "exception_operators_date_numeric_types:runner:ess": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/date_numeric_types/configs/ess.config.ts --grep @ess", - "exception_operators_keyword_text_long:server:serverless": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/exceptions/operators_data_types/keyword_text_long/configs/serverless.config.ts", - "exception_operators_keyword_text_long:runner:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/keyword_text_long/configs/serverless.config.ts --grep @serverless --grep @brokenInServerless --invert", - "exception_operators_keyword_text_long:qa:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/keyword_text_long/configs/serverless.config.ts --grep @serverless --grep '@brokenInServerless|@skipInQA' --invert", - "exception_operators_keyword_text_long:server:ess": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/exceptions/operators_data_types/keyword_text_long/configs/ess.config.ts", - "exception_operators_keyword_text_long:runner:ess": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/keyword_text_long/configs/ess.config.ts --grep @ess", - "exception_operators_ips_text_array:server:serverless": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/exceptions/operators_data_types/ips_text_array/configs/serverless.config.ts", - "exception_operators_ips_text_array:runner:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/ips_text_array/configs/serverless.config.ts --grep @serverless --grep @brokenInServerless --invert", - "exception_operators_ips_text_array:qa:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/ips_text_array/configs/serverless.config.ts --grep @serverless --grep '@brokenInServerless|@skipInQA' --invert", - "exception_operators_ips_text_array:server:ess": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/exceptions/operators_data_types/ips_text_array/configs/ess.config.ts", - "exception_operators_ips_text_array:runner:ess": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/exceptions/operators_data_types/ips_text_array/configs/ess.config.ts --grep @ess", - "rule_creation:server:serverless": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/rule_creation/configs/serverless.config.ts", - "rule_creation:runner:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/rule_creation/configs/serverless.config.ts --grep @serverless --grep @brokenInServerless --invert", - "rule_creation:qa:serverless": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/rule_creation/configs/serverless.config.ts --grep @serverless --grep '@brokenInServerless|@skipInQA' --invert", - "rule_creation:server:ess": "node ../../../scripts/functional_tests_server.js --config ./test_suites/detections_response/default_license/rule_creation/configs/ess.config.ts", - "rule_creation:runner:ess": "node ../../../scripts/functional_test_runner --config=test_suites/detections_response/default_license/rule_creation/configs/ess.config.ts --grep @ess" + "initialize-server": "node ./scripts/index.js server", + "run-tests": "node ./scripts/index.js runner", + "exception_workflows:server:serverless": "npm run initialize-server exceptions/workflows serverless", + "exception_workflows:runner:serverless": "npm run run-tests exceptions/workflows serverless serverlessEnv", + "exception_workflows:qa:serverless": "npm run run-tests exceptions/workflows serverless qaEnv", + "exception_workflows:server:ess": "npm run initialize-server exceptions/workflows ess", + "exception_workflows:runner:ess": "npm run run-tests exceptions/workflows ess essEnv", + "exception_operators_date_numeric_types:server:serverless": "npm run initialize-server exceptions/operators_data_types/date_numeric_types serverless", + "exception_operators_date_numeric_types:runner:serverless": "npm run run-tests exceptions/operators_data_types/date_numeric_types serverless serverlessEnv", + "exception_operators_date_numeric_types:qa:serverless": "npm run run-tests exceptions/operators_data_types/date_numeric_types serverless qaEnv", + "exception_operators_date_numeric_types:server:ess": "npm run initialize-server exceptions/operators_data_types/date_numeric_types ess", + "exception_operators_date_numeric_types:runner:ess": "npm run run-tests exceptions/operators_data_types/date_numeric_types ess essEnv", + "exception_operators_keyword_text_long:server:serverless": "npm run initialize-server exceptions/operators_data_types/keyword_text_long serverless", + "exception_operators_keyword_text_long:runner:serverless": "npm run run-tests exceptions/operators_data_types/keyword_text_long serverless serverlessEnv", + "exception_operators_keyword_text_long:qa:serverless": "npm run run-tests exceptions/operators_data_types/keyword_text_long serverless qaEnv", + "exception_operators_keyword_text_long:server:ess": "npm run initialize-server exceptions/operators_data_types/keyword_text_long ess", + "exception_operators_keyword_text_long:runner:ess": "npm run run-tests exceptions/operators_data_types/keyword_text_long ess essEnv", + "exception_operators_ips_text_array:server:serverless": "npm run initialize-server exceptions/operators_data_types/ips_text_array serverless", + "exception_operators_ips_text_array:runner:serverless": "npm run run-tests exceptions/operators_data_types/ips_text_array serverless serverlessEnv", + "exception_operators_ips_text_array:qa:serverless": "npm run run-tests exceptions/operators_data_types/ips_text_array serverless qaEnv", + "exception_operators_ips_text_array:server:ess": "npm run initialize-server exceptions/operators_data_types/ips_text_array ess", + "exception_operators_ips_text_array:runner:ess": "npm run run-tests exceptions/operators_data_types/ips_text_array ess essEnv", + "rule_creation:server:serverless": "npm run initialize-server rule_creation serverless", + "rule_creation:runner:serverless": "npm run run-tests rule_creation serverless serverlessEnv", + "rule_creation:qa:serverless": "npm run run-tests rule_creation serverless qaEnv", + "rule_creation:server:ess": "npm run initialize-server rule_creation ess", + "rule_creation:runner:ess": "npm run run-tests rule_creation ess essEnv" } } diff --git a/x-pack/test/security_solution_api_integration/scripts/index.js b/x-pack/test/security_solution_api_integration/scripts/index.js new file mode 100644 index 00000000000000..635c135e2c8b17 --- /dev/null +++ b/x-pack/test/security_solution_api_integration/scripts/index.js @@ -0,0 +1,57 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +const { spawn } = require('child_process'); + +const [ + , + , + type, + folder, + projectType, + environment, + area = 'detections_response', + licenseFolder = 'default_license', + ...args +] = process.argv; + +const configPath = `./test_suites/${area}/${licenseFolder}/${folder}/configs/${projectType}.config.ts`; + +const command = + type === 'server' + ? '../../scripts/functional_tests_server.js' + : '../../scripts/functional_test_runner'; + +let grepArgs = []; + +if (type !== 'server') { + switch (environment) { + case 'serverlessEnv': + grepArgs = ['--grep', '@serverless', '--grep', '@brokenInServerless', '--invert']; + break; + + case 'essEnv': + grepArgs = ['--grep', '@ess']; + break; + + case 'qaEnv': + grepArgs = ['--grep', '@serverless', '--grep', '@brokenInServerless|@skipInQA', '--invert']; + break; + + default: + console.error(`Unsupported environment: ${environment}`); + process.exit(1); + } +} + +const child = spawn('node', [command, '--config', configPath, ...grepArgs, ...args], { + stdio: 'inherit', +}); + +child.on('close', (code) => { + console.log(`child process exited with code ${code}`); +}); diff --git a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_new_terms.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_new_terms.ts similarity index 86% rename from x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_new_terms.ts rename to x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_new_terms.ts index d96fbc6beb55bc..459b0e656fae00 100644 --- a/x-pack/test/detection_engine_api_integration/security_and_spaces/group1/create_new_terms.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_new_terms.ts @@ -9,10 +9,10 @@ import expect from '@kbn/expect'; import { DETECTION_ENGINE_RULES_URL } from '@kbn/security-solution-plugin/common/constants'; import { getCreateNewTermsRulesSchemaMock } from '@kbn/security-solution-plugin/common/api/detection_engine/model/rule_schema/mocks'; -import { FtrProviderContext } from '../../common/ftr_provider_context'; + import { deleteAllRules } from '../../utils'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; -// eslint-disable-next-line import/no-default-export export default ({ getService }: FtrProviderContext) => { const supertest = getService('supertest'); const log = getService('log'); @@ -20,11 +20,13 @@ export default ({ getService }: FtrProviderContext) => { /** * Specific api integration tests for new terms rule type */ - describe('create_new_terms', () => { - afterEach(async () => { + describe('@serverless @ess create_new_terms', () => { + beforeEach(async () => { + await deleteAllRules(supertest, log); + }); + after(async () => { await deleteAllRules(supertest, log); }); - it('should not be able to create a new terms rule with too small history window', async () => { const rule = { ...getCreateNewTermsRulesSchemaMock('rule-1'), @@ -56,7 +58,7 @@ export default ({ getService }: FtrProviderContext) => { expect(response.status).to.equal(400); expect(response.body.message).to.be( - '[request body]: Array size (4) is out of bounds: min: 1, max: 3' + '[request body]: new_terms_fields: Array must contain at most 3 element(s)' ); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts index 7bd58191bb8c4b..97b602c4db6175 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/create_rules.ts @@ -467,7 +467,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body).to.eql({ error: 'Bad Request', - message: '[request body]: Invalid value "undefined" supplied to "threshold"', + message: '[request body]: Invalid input', statusCode: 400, }); }); @@ -510,7 +510,7 @@ export default ({ getService }: FtrProviderContext) => { expect(body).to.eql({ error: 'Bad Request', - message: '[request body]: Invalid value "0" supplied to "threshold,value"', + message: '[request body]: threshold.value: Number must be greater than or equal to 1', statusCode: 400, }); }); @@ -574,9 +574,7 @@ export default ({ getService }: FtrProviderContext) => { .send(rule) .expect(400); - expect(body.message).to.eql( - '[request body]: Invalid value "["host.name"]" supplied to "investigation_fields"' - ); + expect(body.message).to.eql('[request body]: Invalid input'); }); }); }); diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/index.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/index.ts index 49268f31ed9f90..a3e706c580e5c6 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/index.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/default_license/rule_creation/index.ts @@ -9,5 +9,6 @@ import { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { describe('Rule creation API', function () { loadTestFile(require.resolve('./create_rules')); + loadTestFile(require.resolve('./create_new_terms')); }); } diff --git a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/remove_uuid_from_actions.ts b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/remove_uuid_from_actions.ts index 08d95bc7502125..7f49c65ff8a253 100644 --- a/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/remove_uuid_from_actions.ts +++ b/x-pack/test/security_solution_api_integration/test_suites/detections_response/utils/actions/remove_uuid_from_actions.ts @@ -5,9 +5,9 @@ * 2.0. */ -import { RuleActionArray } from '@kbn/securitysolution-io-ts-alerting-types'; +import { RuleAction } from '@kbn/security-solution-plugin/common/api/detection_engine'; -export const removeUUIDFromActions = (actions: RuleActionArray): RuleActionArray => { +export const removeUUIDFromActions = (actions: RuleAction[]): RuleAction[] => { return actions.map(({ uuid, ...restOfAction }) => ({ ...restOfAction, })); diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts index d6e61120d7dd9f..635e402bfc45e7 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/exceptions/shared_exception_lists_management/manage_exceptions.cy.ts @@ -20,6 +20,10 @@ import { submitEditedExceptionItem, submitNewExceptionItem, deleteFirstExceptionItemInListDetailPage, + dismissExceptionItemErrorCallOut, + addExceptionHugeComment, + submitNewExceptionItemWithFailure, + editExceptionComment, } from '../../../tasks/exceptions'; import { EXCEPTIONS_URL } from '../../../urls/navigation'; @@ -38,6 +42,7 @@ import { waitForExceptionsTableToBeLoaded, } from '../../../tasks/exceptions_table'; import { visitRuleDetailsPage } from '../../../tasks/rule_details'; +import { closeErrorToast } from '../../../tasks/alerts_detection_rules'; // TODO: https://github.com/elastic/kibana/issues/161539 // FLAKY: https://github.com/elastic/kibana/issues/165795 @@ -147,6 +152,59 @@ describe( cy.get(EMPTY_EXCEPTIONS_VIEWER).should('exist'); }); + + it('should handle huge text as a comment gracefully and allow user create exception item after user updates the comment', function () { + createSharedExceptionList( + { name: 'Newly created list', description: 'This is my list.' }, + true + ); + + // After creation - directed to list detail page + cy.get(EXCEPTIONS_LIST_MANAGEMENT_NAME).should('have.text', EXCEPTION_LIST_NAME); + + // Go back to Shared Exception List + visit(EXCEPTIONS_URL); + + // Click on "Create shared exception list" button on the header + // Click on "Create exception item" + addExceptionListFromSharedExceptionListHeaderMenu(); + + // Add exception item name + addExceptionFlyoutItemName(exceptionName); + + // Add Condition + editException(FIELD_DIFFERENT_FROM_EXISTING_ITEM_FIELD, 0, 0); + + // select shared list radio option and select the first one + linkFirstSharedListOnExceptionFlyout(); + + // add exception comment which is super long + addExceptionHugeComment([...new Array(5000).keys()].map((_) => `Test text!`).join('')); + + // submit + submitNewExceptionItemWithFailure(); + + // Failed to add exception due to comment length and submit button should be disabled + cy.get(CONFIRM_BTN).should('have.attr', 'disabled'); + + // Close error toast + closeErrorToast(); + + // Dismiss error callout + dismissExceptionItemErrorCallOut(); + + // Submit button should be enabled after we dismissed error callout + cy.get(CONFIRM_BTN).should('not.have.attr', 'disabled'); + + // update exception comment to a reasonable (length wise) text + editExceptionComment('Exceptional comment'); + + // submit + submitNewExceptionItem(); + + // New exception is added to the new List + findSharedExceptionListItemsByName(`${EXCEPTION_LIST_NAME}`, [exceptionName]); + }); }); } ); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts index f60bf986991ad9..dc7cbb4b08dfc8 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/exceptions.ts @@ -270,3 +270,8 @@ export const EXCEPTION_ITEM_OVERFLOW_ACTION_DELETE = export const EXECPTION_ITEM_CARD_HEADER_TITLE = '[data-test-subj="exceptionItemCardHeaderTitle"]'; export const EMPTY_EXCEPTIONS_VIEWER = '[data-test-subj="emptyViewerState"]'; + +export const EXCEPTIONS_ITEM_ERROR_CALLOUT = '[data-test-subj="addExceptionErrorCallOut"]'; + +export const EXCEPTIONS_ITEM_ERROR_DISMISS_BUTTON = + '[data-test-subj="addExceptionErrorDismissButton"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts index 909b1bfcf4c5d7..97df4c9af323e4 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/exceptions.ts @@ -44,6 +44,8 @@ import { EXCEPTION_ITEM_HEADER_ACTION_MENU, EXCEPTION_ITEM_OVERFLOW_ACTION_EDIT, EXCEPTION_ITEM_OVERFLOW_ACTION_DELETE, + EXCEPTIONS_ITEM_ERROR_CALLOUT, + EXCEPTIONS_ITEM_ERROR_DISMISS_BUTTON, } from '../screens/exceptions'; export const assertNumberOfExceptionItemsExists = (numberOfItems: number) => { @@ -187,6 +189,12 @@ export const submitNewExceptionItem = () => { cy.get(CONFIRM_BTN).should('not.exist'); }; +export const submitNewExceptionItemWithFailure = () => { + cy.get(CONFIRM_BTN).should('exist'); + cy.get(CONFIRM_BTN).click(); + cy.get(CONFIRM_BTN).should('exist'); +}; + export const submitEditedExceptionItem = () => { cy.get(EXCEPTION_EDIT_FLYOUT_SAVE_BTN).click(); cy.get(EXCEPTION_EDIT_FLYOUT_SAVE_BTN).should('not.exist'); @@ -214,6 +222,19 @@ export const addExceptionComment = (comment: string) => { cy.get(EXCEPTION_COMMENT_TEXT_AREA).should('have.value', comment); }; +export const addExceptionHugeComment = (comment: string) => { + cy.get(EXCEPTION_COMMENTS_ACCORDION_BTN).click(); + cy.get(EXCEPTION_COMMENT_TEXT_AREA).invoke('val', comment); + cy.get(EXCEPTION_COMMENT_TEXT_AREA).type(`!{backspace}`); + cy.get(EXCEPTION_COMMENT_TEXT_AREA).should('have.value', comment); +}; + +export const editExceptionComment = (comment: string) => { + cy.get(EXCEPTION_COMMENT_TEXT_AREA).clear(); + cy.get(EXCEPTION_COMMENT_TEXT_AREA).type(`${comment}`); + cy.get(EXCEPTION_COMMENT_TEXT_AREA).should('have.value', comment); +}; + export const validateExceptionCommentCountAndText = (count: number, comment: string) => { cy.get(EXCEPTION_COMMENTS_ACCORDION_BTN).contains('h3', count); cy.get(EXCEPTION_COMMENT_TEXT_AREA).contains('textarea', comment); @@ -299,3 +320,13 @@ export const validateHighlightedFieldsPopulatedAsExceptionConditions = ( ) => { return highlightedFields.every((field) => validateExceptionConditionField(field)); }; + +export const dismissExceptionItemErrorCallOut = () => { + cy.get(EXCEPTIONS_ITEM_ERROR_CALLOUT).should( + 'include.text', + 'An error occured submitting exception' + ); + + // Click dismiss button + cy.get(EXCEPTIONS_ITEM_ERROR_DISMISS_BUTTON).click(); +}; diff --git a/x-pack/test/security_solution_endpoint/services/endpoint.ts b/x-pack/test/security_solution_endpoint/services/endpoint.ts index 1f66ab6ac8ed5e..1372ffe0139fd4 100644 --- a/x-pack/test/security_solution_endpoint/services/endpoint.ts +++ b/x-pack/test/security_solution_endpoint/services/endpoint.ts @@ -25,7 +25,7 @@ import { indexHostsAndAlerts, } from '@kbn/security-solution-plugin/common/endpoint/index_data'; import { getEndpointPackageInfo } from '@kbn/security-solution-plugin/common/endpoint/utils/package'; -import { isEndpointPackageV2 } from '@kbn/security-solution-plugin/common/endpoint/utils/transforms'; +import { isEndpointPackageV2 } from '@kbn/security-solution-plugin/common/endpoint/utils/package_v2'; import { installOrUpgradeEndpointFleetPackage } from '@kbn/security-solution-plugin/common/endpoint/data_loaders/setup_fleet_for_endpoint'; import { EndpointError } from '@kbn/security-solution-plugin/common/endpoint/errors'; import { STARTED_TRANSFORM_STATES } from '@kbn/security-solution-plugin/common/constants'; diff --git a/x-pack/test_serverless/api_integration/test_suites/common/alerting/summary_actions.ts b/x-pack/test_serverless/api_integration/test_suites/common/alerting/summary_actions.ts index 45073d50a1f3d3..1885c951b81f10 100644 --- a/x-pack/test_serverless/api_integration/test_suites/common/alerting/summary_actions.ts +++ b/x-pack/test_serverless/api_integration/test_suites/common/alerting/summary_actions.ts @@ -41,6 +41,9 @@ export default function ({ getService }: FtrProviderContext) { const esDeleteAllIndices = getService('esDeleteAllIndices'); describe('Summary actions', function () { + // flaky on MKI, see https://github.com/elastic/kibana/issues/169204 + this.tags(['failsOnMKI']); + const RULE_TYPE_ID = '.es-query'; const ALERT_ACTION_INDEX = 'alert-action-es-query'; const ALERT_INDEX = '.alerts-stack.alerts-default'; diff --git a/x-pack/test_serverless/functional/test_suites/common/examples/search/warnings.ts b/x-pack/test_serverless/functional/test_suites/common/examples/search/warnings.ts index ff24321f11348a..a254cb753c8645 100644 --- a/x-pack/test_serverless/functional/test_suites/common/examples/search/warnings.ts +++ b/x-pack/test_serverless/functional/test_suites/common/examples/search/warnings.ts @@ -7,7 +7,6 @@ import type { estypes } from '@elastic/elasticsearch'; import expect from '@kbn/expect'; -import { asyncForEach } from '@kbn/std'; import assert from 'assert'; import type { WebElementWrapper } from '../../../../../../../test/functional/services/lib/web_element_wrapper'; import type { FtrProviderContext } from '../../../../ftr_provider_context'; @@ -107,16 +106,9 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async () => { const toasts = await find.allByCssSelector(toastsSelector); expect(toasts.length).to.be(2); - const expects = ['Results are partial and may be incomplete.', 'Query result']; - await asyncForEach(toasts, async (t, index) => { - expect(await t.getVisibleText()).to.eql(expects[index]); - }); + await testSubjects.click('viewWarningBtn'); }); - // click "see full error" button in the toast - const [openShardModalButton] = await testSubjects.findAll('viewWarningBtn'); - await openShardModalButton.click(); - // request await retry.try(async () => { await testSubjects.click('inspectorRequestDetailRequest'); @@ -164,10 +156,6 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await retry.try(async () => { toasts = await find.allByCssSelector(toastsSelector); expect(toasts.length).to.be(2); - const expects = ['Results are partial and may be incomplete.', 'Query result']; - await asyncForEach(toasts, async (t, index) => { - expect(await t.getVisibleText()).to.eql(expects[index]); - }); }); // warnings tab diff --git a/x-pack/test_serverless/functional/test_suites/common/management/transforms/search_bar_features.ts b/x-pack/test_serverless/functional/test_suites/common/management/transforms/search_bar_features.ts index 995d17a6dc2c4e..124fe461d53069 100644 --- a/x-pack/test_serverless/functional/test_suites/common/management/transforms/search_bar_features.ts +++ b/x-pack/test_serverless/functional/test_suites/common/management/transforms/search_bar_features.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation']); + const PageObjects = getPageObjects(['header', 'svlCommonPage', 'svlCommonNavigation']); const allLabels = [{ search: 'transform', label: 'Data / Transforms', expected: true }]; const expectedLabels = allLabels.filter((l) => l.expected); @@ -26,6 +26,7 @@ export default function ({ getPageObjects }: FtrProviderContext) { describe('list features', () => { if (expectedLabels.length > 0) { it('has the correct features enabled', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.svlCommonNavigation.search.showSearch(); for (const expectedLabel of expectedLabels) { @@ -44,6 +45,7 @@ export default function ({ getPageObjects }: FtrProviderContext) { if (notExpectedLabels.length > 0) { it('has the correct features disabled', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.svlCommonNavigation.search.showSearch(); for (const notExpectedLabel of notExpectedLabels) { diff --git a/x-pack/test_serverless/functional/test_suites/observability/ml/search_bar_features.ts b/x-pack/test_serverless/functional/test_suites/observability/ml/search_bar_features.ts index d3899b6d45073e..2f277eb084559a 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/ml/search_bar_features.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/ml/search_bar_features.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation']); + const PageObjects = getPageObjects(['header', 'svlCommonPage', 'svlCommonNavigation']); const allLabels = [ { label: 'Machine Learning', expected: true }, @@ -49,6 +49,7 @@ export default function ({ getPageObjects }: FtrProviderContext) { describe('list features', () => { it('has the correct features enabled', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.svlCommonNavigation.search.showSearch(); const expectedLabels = allLabels.filter((l) => l.expected).map((l) => l.label); @@ -64,7 +65,9 @@ export default function ({ getPageObjects }: FtrProviderContext) { } await PageObjects.svlCommonNavigation.search.hideSearch(); }); + it('has the correct features disabled', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.svlCommonNavigation.search.showSearch(); const notExpectedLabels = allLabels.filter((l) => !l.expected).map((l) => l.label); diff --git a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts index 59f0554cd85ac6..4b94df8c51bcc6 100644 --- a/x-pack/test_serverless/functional/test_suites/observability/navigation.ts +++ b/x-pack/test_serverless/functional/test_suites/observability/navigation.ts @@ -127,6 +127,18 @@ export default function ({ getPageObject, getService }: FtrProviderContext) { await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Cases', 'Settings']); }); + it('navigates to alerts app', async () => { + await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'observability-overview:alerts' }); + await svlCommonNavigation.sidenav.expectLinkActive({ + deepLinkId: 'observability-overview:alerts', + }); + await testSubjects.click('manageRulesPageButton'); + await svlCommonNavigation.breadcrumbs.expectBreadcrumbTexts(['Alerts', 'Rules']); + await svlCommonNavigation.sidenav.expectLinkActive({ + deepLinkId: 'observability-overview:alerts', + }); + }); + it('navigates to integrations', async () => { await svlCommonNavigation.sidenav.openSection('project_settings_project_nav'); await svlCommonNavigation.sidenav.clickLink({ deepLinkId: 'integrations' }); diff --git a/x-pack/test_serverless/functional/test_suites/search/ml/search_bar_features.ts b/x-pack/test_serverless/functional/test_suites/search/ml/search_bar_features.ts index f410b4c1668c6a..cdedf3248c1914 100644 --- a/x-pack/test_serverless/functional/test_suites/search/ml/search_bar_features.ts +++ b/x-pack/test_serverless/functional/test_suites/search/ml/search_bar_features.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation']); + const PageObjects = getPageObjects(['header', 'svlCommonPage', 'svlCommonNavigation']); const allLabels = [ { label: 'Machine Learning', expected: true }, @@ -49,6 +49,7 @@ export default function ({ getPageObjects }: FtrProviderContext) { describe('list features', () => { it('has the correct features enabled', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.svlCommonNavigation.search.showSearch(); const expectedLabels = allLabels.filter((l) => l.expected).map((l) => l.label); @@ -64,7 +65,9 @@ export default function ({ getPageObjects }: FtrProviderContext) { } await PageObjects.svlCommonNavigation.search.hideSearch(); }); + it('has the correct features disabled', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.svlCommonNavigation.search.showSearch(); const notExpectedLabels = allLabels.filter((l) => !l.expected).map((l) => l.label); diff --git a/x-pack/test_serverless/functional/test_suites/security/ml/search_bar_features.ts b/x-pack/test_serverless/functional/test_suites/security/ml/search_bar_features.ts index a8571be2daeda3..8d48ba2632731f 100644 --- a/x-pack/test_serverless/functional/test_suites/security/ml/search_bar_features.ts +++ b/x-pack/test_serverless/functional/test_suites/security/ml/search_bar_features.ts @@ -8,7 +8,7 @@ import expect from '@kbn/expect'; import { FtrProviderContext } from '../../../ftr_provider_context'; export default function ({ getPageObjects }: FtrProviderContext) { - const PageObjects = getPageObjects(['svlCommonPage', 'svlCommonNavigation']); + const PageObjects = getPageObjects(['header', 'svlCommonPage', 'svlCommonNavigation']); const allLabels = [ { label: 'Machine Learning', expected: true }, @@ -49,6 +49,7 @@ export default function ({ getPageObjects }: FtrProviderContext) { describe('list features', () => { it('has the correct features enabled', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.svlCommonNavigation.search.showSearch(); const expectedLabels = allLabels.filter((l) => l.expected).map((l) => l.label); @@ -64,7 +65,9 @@ export default function ({ getPageObjects }: FtrProviderContext) { } await PageObjects.svlCommonNavigation.search.hideSearch(); }); + it('has the correct features disabled', async () => { + await PageObjects.header.waitUntilLoadingHasFinished(); await PageObjects.svlCommonNavigation.search.showSearch(); const notExpectedLabels = allLabels.filter((l) => !l.expected).map((l) => l.label); diff --git a/x-pack/test_serverless/tsconfig.json b/x-pack/test_serverless/tsconfig.json index 21ca495a87eaf6..e587356636d610 100644 --- a/x-pack/test_serverless/tsconfig.json +++ b/x-pack/test_serverless/tsconfig.json @@ -56,7 +56,6 @@ "@kbn/es-archiver", "@kbn/rule-data-utils", "@kbn/rison", - "@kbn/std", "@kbn/serverless-common-settings", "@kbn/serverless-observability-settings", "@kbn/serverless-search-settings", diff --git a/yarn.lock b/yarn.lock index 28df3eac7c3f25..af448bc28a07ff 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6204,6 +6204,10 @@ version "0.0.0" uid "" +"@kbn/zod-helpers@link:packages/kbn-zod-helpers": + version "0.0.0" + uid "" + "@kwsites/file-exists@^1.1.1": version "1.1.1" resolved "https://registry.yarnpkg.com/@kwsites/file-exists/-/file-exists-1.1.1.tgz#ad1efcac13e1987d8dbaf235ef3be5b0d96faa99" @@ -13576,9 +13580,9 @@ crypto-browserify@^3.11.0: randomfill "^1.0.3" crypto-js@^4.0.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" - integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== + version "4.2.0" + resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== crypto-random-string@^1.0.0: version "1.0.0"