diff --git a/.buildkite/pipelines/on_merge.yml b/.buildkite/pipelines/on_merge.yml index 2963f1c9ba1d6..8b00db428a713 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 3cff06507bc6d..3db3da975b41b 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 45778427741c1..94c28c9b47d9b 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 8fa51a4f4d23c..147569b595dc9 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 4bc7e1f760277..82193a7e2ecb7 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 87004fdbe855a..fb41f6d904b10 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 3dac6db711d1a..488707c72c7c4 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-27 +date: 2023-10-30 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 c5812ae13ec60..8c678bcef2c68 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-27 +date: 2023-10-30 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 9c1ecce50df4a..8bfec524f8a14 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-27 +date: 2023-10-30 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 649da598ed7c3..e8dc3c4d97182 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-27 +date: 2023-10-30 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 f7eb17ed97ab4..7857a694cffbe 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-27 +date: 2023-10-30 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 2082f37fa6a72..a51abe4edc3e7 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-27 +date: 2023-10-30 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 f36abd5c12ae6..a003c483bc7a1 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-27 +date: 2023-10-30 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 942b6e66bddae..e82fd28a18ca4 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-27 +date: 2023-10-30 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 46f77dfaa933b..72f98eb51ac77 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-27 +date: 2023-10-30 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 0cde5e37652f6..758dd725c9c8e 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-27 +date: 2023-10-30 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 d9ea53be07b90..3e0f1266d51ff 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-27 +date: 2023-10-30 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 cebee0da1d3e2..d84bbdb25757e 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-27 +date: 2023-10-30 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 1c3bee7b51f69..9647bb7eb1574 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-27 +date: 2023-10-30 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 977011e374c2c..02226114f2f60 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-27 +date: 2023-10-30 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 2716d97a54403..c5c8592c4e821 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-27 +date: 2023-10-30 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 632cd609815e5..d8cf5e54c61f0 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-27 +date: 2023-10-30 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 a451c8bad5500..82af6f595f3d1 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-27 +date: 2023-10-30 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 8936c27822706..2e431b9effeff 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-27 +date: 2023-10-30 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 8463cd00ebad8..7e8bc34988b14 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-27 +date: 2023-10-30 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 e606fb75730db..14fddf0acfbd4 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-27 +date: 2023-10-30 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 c29d8c886558d..05a6ebfa7c57a 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-27 +date: 2023-10-30 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 8bec8a0662436..5e9f944af1925 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-27 +date: 2023-10-30 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 9eb57a717edd8..4f39935a0edd8 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'dashboardEnhanced'] --- import dashboardEnhancedObj from './dashboard_enhanced.devdocs.json'; diff --git a/api_docs/data.mdx b/api_docs/data.mdx index 1192532d971da..01e33e0c93817 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data'] --- import dataObj from './data.devdocs.json'; diff --git a/api_docs/data_query.mdx b/api_docs/data_query.mdx index 8a94abf08b851..acf7d5884e94b 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.query'] --- import dataQueryObj from './data_query.devdocs.json'; diff --git a/api_docs/data_search.mdx b/api_docs/data_search.mdx index 34f5823cd5a2b..c9d5664e4dd33 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'data.search'] --- import dataSearchObj from './data_search.devdocs.json'; diff --git a/api_docs/data_view_editor.mdx b/api_docs/data_view_editor.mdx index 53b7007c0b1d4..9ad095932eb2e 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-27 +date: 2023-10-30 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 021a77b173a0e..8c8d602065e5c 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-27 +date: 2023-10-30 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 9524f06f05c64..d48436e2b0916 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-27 +date: 2023-10-30 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 3d3c5588810e4..ba5771edf96f0 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-27 +date: 2023-10-30 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 beecf7c270049..bbd7d6093d771 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-27 +date: 2023-10-30 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 e959af8879df8..a4f897b735dec 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_plugin.mdx b/api_docs/deprecations_by_plugin.mdx index a3532a3593c97..43b928ddc2a96 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/deprecations_by_team.mdx b/api_docs/deprecations_by_team.mdx index 06784361a491e..86341bbaff5c8 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana'] --- diff --git a/api_docs/dev_tools.mdx b/api_docs/dev_tools.mdx index 3a728ab023ce7..c433c4387f5eb 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-27 +date: 2023-10-30 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 f4f4ba905b79a..52a23675fb770 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 diff --git a/api_docs/discover.mdx b/api_docs/discover.mdx index a03c7e9f606d8..9b9dafae2d94a 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-27 +date: 2023-10-30 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 6db322fb30c39..4cdde823bd6d9 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-27 +date: 2023-10-30 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 f51d908d40338..81a691ce8c51e 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-27 +date: 2023-10-30 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 3359e7d46cb40..8468b63b75084 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-27 +date: 2023-10-30 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 cd21134417976..bd857df2dcf0e 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-27 +date: 2023-10-30 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 103435219ddfd..8d04c97b8617b 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-27 +date: 2023-10-30 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 1e81f15f4a446..94f1973c311bd 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-27 +date: 2023-10-30 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 b87998e9ef926..678c3b47d943b 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-27 +date: 2023-10-30 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 e097559761666..16d2bc4cccf3a 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-27 +date: 2023-10-30 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 5c127547543e9..dbb16abeeec10 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-27 +date: 2023-10-30 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 9d53b6f0133de..731bb76589a4b 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-27 +date: 2023-10-30 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 de2de5923fd40..e5f861b138d6a 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-27 +date: 2023-10-30 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 5b88eb90d8cc3..0a43e932cf2c1 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-27 +date: 2023-10-30 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 fe319250cc870..cd01389523fb1 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-27 +date: 2023-10-30 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 a7b1b7bc3c679..6c9ff3ca1c067 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-27 +date: 2023-10-30 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 b95dff352d636..18e2b55dc20cf 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-27 +date: 2023-10-30 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 d4b072e718d63..d1c2f9c001a9e 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-27 +date: 2023-10-30 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 db3d207f511b6..a546ecf448a77 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-27 +date: 2023-10-30 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 e7d1055c337ea..71c52b2e8a0ca 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-27 +date: 2023-10-30 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 0bdfc2f3433b3..769f31d9c4053 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-27 +date: 2023-10-30 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 d0575ec8f6ab2..65fe78ccb2fd8 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-27 +date: 2023-10-30 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 dda5657d2ca54..65e0cd4ed062a 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-27 +date: 2023-10-30 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 acaaf34872c61..f48522e5f4848 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-27 +date: 2023-10-30 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 cab8b9d6f8235..5ce32ac57e1b8 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-27 +date: 2023-10-30 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 e4a3dbd8fe735..f80348f80c25f 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-27 +date: 2023-10-30 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 100389ba525fa..4dd7b63ac58dc 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-27 +date: 2023-10-30 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 ce40bfb60d427..147aea7624cc2 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-27 +date: 2023-10-30 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 b9c70b1c44cf0..8b5c0469a397f 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-27 +date: 2023-10-30 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 31454c3588b2a..80a15632403c1 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-27 +date: 2023-10-30 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 a43665fba8149..658d36c32b613 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-27 +date: 2023-10-30 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 3d280bb7ff81c..e2bda4d7c5450 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-27 +date: 2023-10-30 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 fe0dcdc32b30c..b90b9e2dfc5bd 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-27 +date: 2023-10-30 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 3517302578fed..73debf02781ce 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-27 +date: 2023-10-30 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 48a932b258282..24bcdd8503995 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-27 +date: 2023-10-30 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 74dd6d5ddc3ee..e306f683c6e41 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-27 +date: 2023-10-30 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 7476160ff1ee9..a40057a7e49a5 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-27 +date: 2023-10-30 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 1ac92ae17720e..8f0ea0d827ea2 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-27 +date: 2023-10-30 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 fa4b7d8e9ab77..79fcfcca2867f 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-27 +date: 2023-10-30 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 dd8ed1d1d1603..7f51f3fac8ad1 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'indexManagement'] --- import indexManagementObj from './index_management.devdocs.json'; diff --git a/api_docs/infra.mdx b/api_docs/infra.mdx index b4eca19a50216..f551e67e7c2eb 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-27 +date: 2023-10-30 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 1f4a4ff09da12..720c35e4a6322 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-27 +date: 2023-10-30 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 0896b961db033..0d61903f2b520 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-27 +date: 2023-10-30 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 e28e578abae40..06a149e4f9a68 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-27 +date: 2023-10-30 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 9e7520d437501..cb481fd48aee7 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-27 +date: 2023-10-30 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 ada69b2efc722..b04f8b3ef4abb 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-27 +date: 2023-10-30 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 70b31dfb14cf5..88ef052d8e29e 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-27 +date: 2023-10-30 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 abbb7ee7dadfc..23f3bb5dcdc45 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-27 +date: 2023-10-30 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 1987f618d1bf2..da71ce7dfbaa0 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-27 +date: 2023-10-30 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 aa94fe5178855..2a049d585b7f7 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-27 +date: 2023-10-30 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 3038c4da9e024..00395ebb47e60 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-27 +date: 2023-10-30 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 a1f0340d1b9cc..fe17a6acbe4b5 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-27 +date: 2023-10-30 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 433d19e6f00f6..9e24ca9f836e9 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-27 +date: 2023-10-30 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 94ff13992647b..caa7606acd535 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-27 +date: 2023-10-30 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 c92b3be317c64..f85d3b4fbfdf7 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-27 +date: 2023-10-30 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 7a07691b71da9..1bb53aa514566 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-27 +date: 2023-10-30 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 7f76d52516a31..e2d101fa2d8a0 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-27 +date: 2023-10-30 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 7688cef3dfd87..e537392cac8ae 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-27 +date: 2023-10-30 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 1ed41b33d1e2e..797c771387bd7 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-27 +date: 2023-10-30 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 50895bfaffc04..406d7c1f08d5e 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-27 +date: 2023-10-30 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 b87207d006131..cff634b466c86 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-27 +date: 2023-10-30 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 2c5dc0716b01a..0494f90df5c73 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-27 +date: 2023-10-30 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 427af438e30d5..bcf75d475b8d0 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-27 +date: 2023-10-30 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 d596c7049355c..ec4d16fb32737 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-27 +date: 2023-10-30 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 b4d12a7ac823b..4a4f623de8030 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-27 +date: 2023-10-30 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 d44e6cc48d09b..cf7787d54c791 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-27 +date: 2023-10-30 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 11417d4270dc1..ade31cdd7b5c7 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-27 +date: 2023-10-30 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 46910f335ed1f..b77caf5b15106 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-27 +date: 2023-10-30 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 81226d6f28465..af595436e19ff 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-27 +date: 2023-10-30 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 a43d46ca2da5b..f390193bf64bb 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-27 +date: 2023-10-30 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 ab60496618c8c..7b90958d46af2 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-27 +date: 2023-10-30 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 478349b8fa504..4d8171a9cb8da 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-27 +date: 2023-10-30 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 9ed105c9feefd..3af883ca4ad7c 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-27 +date: 2023-10-30 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 c5467cfbfc1b4..6c996c5fded78 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-27 +date: 2023-10-30 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 2bd121ce36b48..29b858288fb43 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-27 +date: 2023-10-30 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 71d90b8d6688a..60c2e15fd83d3 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-27 +date: 2023-10-30 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 2f0e83226ce92..3e442470b5653 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-27 +date: 2023-10-30 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 e4db6727f5d03..cad94402ff99e 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-27 +date: 2023-10-30 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 c0ce4cd384965..6a2256ca69873 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-27 +date: 2023-10-30 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 b2bb30e032863..3d8f0c3ed9c19 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-27 +date: 2023-10-30 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 3378ab58b1fe5..9c783b9a72f16 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-27 +date: 2023-10-30 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 e5297ab59383d..e89b0d509b6c5 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-27 +date: 2023-10-30 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 860a0ff860740..e0c29ded3d007 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-27 +date: 2023-10-30 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 6fabd7796fd2d..c48947c57ca02 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-27 +date: 2023-10-30 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 3cbf28e2fdd5c..fe0cbc864decc 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-27 +date: 2023-10-30 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 2d63d7419a926..1441a038c1bf8 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-27 +date: 2023-10-30 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 8a7297e70a2f9..e564d1e31b034 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-27 +date: 2023-10-30 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 b2923fc857032..b663184a3015d 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-27 +date: 2023-10-30 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 9e966e5d54c32..dc3d73fe40362 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-27 +date: 2023-10-30 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 9c0a9bcaf3441..66cc933530d80 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-27 +date: 2023-10-30 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 9af860b006905..8dd3efa35f1b1 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-27 +date: 2023-10-30 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 32ea228cf282e..46efbf2f78a5a 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-27 +date: 2023-10-30 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 811e4f8154912..33daf47869838 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-27 +date: 2023-10-30 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 004bd41e56a8a..4d39c1f75a2b5 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-27 +date: 2023-10-30 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 794cf39175913..87c72edb379c7 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-27 +date: 2023-10-30 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 b4c865979673b..20619d398105a 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-27 +date: 2023-10-30 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 6b791f7864232..23268503d2d24 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-27 +date: 2023-10-30 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 ab81011d1ccb1..2e0fe4c80ec18 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-27 +date: 2023-10-30 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 cc1539eb5de86..89755d0831eba 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-27 +date: 2023-10-30 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 532d45aecc440..e2d0093df2db8 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-27 +date: 2023-10-30 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 1bb1c8761fe8c..8a509df7a0554 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-27 +date: 2023-10-30 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 ffba0833f49d0..5bc34f346f3ba 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-27 +date: 2023-10-30 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 95f01d2116d39..e3f2a9229e7ca 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-27 +date: 2023-10-30 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 0b7ecb0a77191..b4082e8a1ece9 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-27 +date: 2023-10-30 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 a01f941292bb1..3418e6c59964f 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-27 +date: 2023-10-30 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 c8470506278fe..bc8e518319ed8 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-27 +date: 2023-10-30 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 9dc6b7664d0b0..9b1d88c663bbe 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-27 +date: 2023-10-30 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 3392826e64ef0..3a24611a94774 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-27 +date: 2023-10-30 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 06f78d2657077..1d84e0df20dce 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-27 +date: 2023-10-30 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 adc5a6cac4ebb..826840450eb6d 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-27 +date: 2023-10-30 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 c90fdb0726463..0d1ed6e1d863d 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-27 +date: 2023-10-30 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 b2544b8b2c0a0..312c9e893804d 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-27 +date: 2023-10-30 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 3e4aa3961a954..92065b8fb5927 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-27 +date: 2023-10-30 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 c4911b8fe6130..6e615237ed389 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-27 +date: 2023-10-30 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 ae4e21df9a8a2..ca041503318db 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-27 +date: 2023-10-30 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 04a0fef25c300..9bb70fd98070e 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-27 +date: 2023-10-30 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 4478522e39bf9..dae5d5a5b8354 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-27 +date: 2023-10-30 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 ac24b7d581cc4..a0d107b9f4a77 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-27 +date: 2023-10-30 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 e1c24de09c0c3..dc18be90b155f 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-27 +date: 2023-10-30 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 069c07fb1e047..4869c84623ffa 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-27 +date: 2023-10-30 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 5a7d583d07638..bdd29273932b1 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-27 +date: 2023-10-30 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 432d5cce70e40..8f20c1a3fcb9c 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-27 +date: 2023-10-30 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 bd09f6b40b5de..628cc422f7bc8 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-27 +date: 2023-10-30 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 0a151195268f1..463e7f84e0d85 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-27 +date: 2023-10-30 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 b80548784df0f..e24a754901533 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-27 +date: 2023-10-30 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 0d9312cbedde6..e4faae5b07fee 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-27 +date: 2023-10-30 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 85793afea3ba9..93f54cf9f8d71 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-27 +date: 2023-10-30 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 3c418b262904a..69dba4fcf8cce 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-27 +date: 2023-10-30 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 0403aaa78a975..57d2788def467 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-27 +date: 2023-10-30 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 daed148b3155d..50d402dd3450e 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-27 +date: 2023-10-30 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 8bd0dc2f7e60b..0ed2120cfc58d 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-27 +date: 2023-10-30 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 26ad610d9e621..44ae37dad4f85 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-27 +date: 2023-10-30 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 0c3461a98d9a7..31ea61c992d33 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-27 +date: 2023-10-30 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 3fe761c7e736f..465f14c2ec718 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-27 +date: 2023-10-30 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 f3d1f0de14737..2d050aba5c93b 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-27 +date: 2023-10-30 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 30f7e6f6ff426..b9b1c77adb8ce 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-27 +date: 2023-10-30 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 22ad7b23a3bf4..c71c78b3bdddd 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-27 +date: 2023-10-30 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 a74947f4622ce..bb071a04642ce 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-27 +date: 2023-10-30 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 b916885cb70d6..0aba16c795657 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-27 +date: 2023-10-30 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 2fc2491c29e91..dbfbd1ab7793a 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-27 +date: 2023-10-30 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 76e838963bb44..f0df9b59915a3 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-27 +date: 2023-10-30 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 8169e3601ed12..7866254094a21 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-27 +date: 2023-10-30 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 92107ac05d7fb..8ce69dbfff76f 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-27 +date: 2023-10-30 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 aef6e3ffac57b..0adc17b77de97 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-27 +date: 2023-10-30 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 b382ec348832b..f02a5a97d8dd5 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-27 +date: 2023-10-30 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 bab7b06c4c1f6..dbae03f28a194 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-27 +date: 2023-10-30 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 a31901372ebc2..7d8b1703441b6 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-27 +date: 2023-10-30 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 a3fbbfaefd677..41cc0b7e84f0d 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-27 +date: 2023-10-30 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 d9bb21666a3e0..1b02f2442240b 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-27 +date: 2023-10-30 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 ae0447e4e0077..5b38e856b8672 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-27 +date: 2023-10-30 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 acd3abd81b3c3..49b083c681418 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 35ca4f5684289..a841844e197c4 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-27 +date: 2023-10-30 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 2f6c7581cf27c..156dbd0ae70b7 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-27 +date: 2023-10-30 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 0726c85dcb6fb..15b88ae735f75 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-27 +date: 2023-10-30 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 dd42774f2dfb0..b6f2936d4dab3 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-27 +date: 2023-10-30 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 12404ede98d30..50664e26523c4 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-27 +date: 2023-10-30 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 dcd1bc35cbd1a..555edf9d8a47d 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-27 +date: 2023-10-30 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 618fb54290ba5..95fdf6a73a907 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-27 +date: 2023-10-30 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 27cc14b41e1eb..e773962603f2e 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-27 +date: 2023-10-30 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 c1e57a3659f37..1513daa8babda 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-27 +date: 2023-10-30 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 a074ee5f8f1e0..84425c06ef055 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-27 +date: 2023-10-30 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 76fa0cc8be2af..a7a12bcdf5d89 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-27 +date: 2023-10-30 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 ad00d790fec94..c621885572337 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-27 +date: 2023-10-30 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 425f213017c2e..59d0bc2c3206c 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-27 +date: 2023-10-30 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 93b536b34032c..00fcf1717fba3 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-27 +date: 2023-10-30 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 1fcd8410a61fc..d9e6faebf798d 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-27 +date: 2023-10-30 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 7d5d7cf065485..0020b982d28d8 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-27 +date: 2023-10-30 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 3d7771483a4de..97883d6b8fb3b 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-27 +date: 2023-10-30 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 89b62748b0e1c..38edee726a6ab 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-27 +date: 2023-10-30 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 043b72b7a8d61..60dab7a60fd5f 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-27 +date: 2023-10-30 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 ead038efdb52b..dae78065fa351 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-27 +date: 2023-10-30 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 76df732c8b759..327e55d5ce680 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-27 +date: 2023-10-30 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 6a78959e1d690..c2502f94cf76e 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-27 +date: 2023-10-30 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 acee6e3484c5c..1d3c92bcee5be 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-27 +date: 2023-10-30 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 f99e3858e8cdb..27e966d2c20c7 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-27 +date: 2023-10-30 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 b652d349acecc..9a712c40a64f0 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-27 +date: 2023-10-30 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 161d7c76eb9f8..ec8363206dd06 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-27 +date: 2023-10-30 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 b7e567619eaa4..bbeeb63f1e4f3 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-27 +date: 2023-10-30 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 f6bec66bf4464..d682ecbad81ae 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-27 +date: 2023-10-30 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 265b4d693a60f..ba54af0f1d69a 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-27 +date: 2023-10-30 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 f56c178bdc87f..5949cc6d2f725 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-27 +date: 2023-10-30 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 f627307ef4c47..a531fb1f3156e 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-27 +date: 2023-10-30 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 a412bbf0165b8..0c6581105eafe 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-27 +date: 2023-10-30 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 8639e3ca79252..01dc87485701e 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-27 +date: 2023-10-30 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 53717453acb1b..c01743d1a198d 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-27 +date: 2023-10-30 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 51afca2c463d1..444a1a6434f28 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-27 +date: 2023-10-30 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 9ec6bd71ac7a9..fd787095decd0 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-27 +date: 2023-10-30 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 5c9fc08f71627..430eed50aea11 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-27 +date: 2023-10-30 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 d795e9ce6cd3f..3afee394976d0 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-27 +date: 2023-10-30 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 de2f21cae3b42..0971be7df5f85 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-27 +date: 2023-10-30 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 db975076828d8..539f99fb148a2 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-27 +date: 2023-10-30 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 899b88ef5a2c5..e1f1b16bc1bdb 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-27 +date: 2023-10-30 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 771ca01add0b6..a12edbc8c883a 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-27 +date: 2023-10-30 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 310cb9b4da2f1..dde6b10fc3890 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-27 +date: 2023-10-30 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 5e417b87e7923..d914ba2025ed6 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-27 +date: 2023-10-30 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 b1b22a659865c..c7afd682007ba 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-27 +date: 2023-10-30 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 6d47fb6eb40a1..473cb188345bb 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-27 +date: 2023-10-30 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 3b468422185bd..c1cd312f762c7 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-27 +date: 2023-10-30 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 9e13265b25aca..165724bf8ebeb 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-27 +date: 2023-10-30 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 2db86ac9ab806..8640b1316bf93 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-27 +date: 2023-10-30 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 4cba53098d140..dc396a491a87e 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-27 +date: 2023-10-30 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 efa7fcf7e4a55..bc112237aeaf2 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-27 +date: 2023-10-30 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 f559cd6bbea48..83a74527e2aa4 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-27 +date: 2023-10-30 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 b0d92313c9a26..722772a171965 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-27 +date: 2023-10-30 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 91575b9ff0c10..89dfdf9310a34 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-27 +date: 2023-10-30 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 3f220d07bf55d..ba4f03c18a8c5 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-27 +date: 2023-10-30 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 98b492d853e2d..bd1b61ebf7bbc 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-27 +date: 2023-10-30 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 8516c02a112b2..6b7dc87819436 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-27 +date: 2023-10-30 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 890a0ccf3df78..a75e860a678fb 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-27 +date: 2023-10-30 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 ed7672ebe9c6a..6f0935e5abfed 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-27 +date: 2023-10-30 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 9713898be6e93..dd0b9c1db6bcc 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-27 +date: 2023-10-30 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 d74e9cffdd6da..fdfdfac1c8153 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-27 +date: 2023-10-30 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 5ff6fac99ec02..11beadbff025f 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-27 +date: 2023-10-30 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 56b60cef50f62..a37041471d99c 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-27 +date: 2023-10-30 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 8d8092669b3bf..27f5183138fd3 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-27 +date: 2023-10-30 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 b007b5f5d0ee9..41d776b832b68 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-27 +date: 2023-10-30 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 0407a130c4d75..e28e8c1b98d9f 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-27 +date: 2023-10-30 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 1165de02e07e6..e7716dab09999 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-27 +date: 2023-10-30 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 73d038343302e..3ca818d798892 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-27 +date: 2023-10-30 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 453f84629f29d..c1361a1f97780 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-27 +date: 2023-10-30 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 7519fd4a14b84..1592f0fa18dc7 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-27 +date: 2023-10-30 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 8aa990847dccf..c8d074ce70041 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-27 +date: 2023-10-30 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 0c82f7077d52b..f969f529d9605 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-27 +date: 2023-10-30 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 ae6d2cb9b3162..f4dbf57610a3d 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-27 +date: 2023-10-30 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 737a7df5284b4..cced11d4b9737 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-27 +date: 2023-10-30 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 dffab368561ca..4a82583cb00de 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-27 +date: 2023-10-30 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 2def63025e8fd..f99bf236876b4 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-27 +date: 2023-10-30 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 7b8f8a87292bc..ff3a9e51ebe24 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-27 +date: 2023-10-30 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 2ec4b98cf31bb..a7a89594c3434 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-27 +date: 2023-10-30 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 dff77b94eb114..d5211f3881536 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-27 +date: 2023-10-30 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 96bae59acd5d2..071ecb9918cb5 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-27 +date: 2023-10-30 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 75cf85d1dcbb3..425772070ebe6 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-27 +date: 2023-10-30 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 0c62788547149..73f3fc02b96b5 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-27 +date: 2023-10-30 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 b277b24f2a819..5e0c8fe1614f2 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-27 +date: 2023-10-30 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 9febb3391cfd3..edb4314e119a7 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-27 +date: 2023-10-30 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 a12a412bb0e71..ff7d151e4aaac 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-27 +date: 2023-10-30 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 cc53aa4ad8b1e..18cb0d3d63d15 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-27 +date: 2023-10-30 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 47a505dd77700..51704a345a8b2 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-27 +date: 2023-10-30 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 7bb54df01a626..4b8dab956369a 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-27 +date: 2023-10-30 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 b42f07fb74348..b8d3aa1d77bdc 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-27 +date: 2023-10-30 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 f1c9c3e21f085..bed67baa8df17 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-27 +date: 2023-10-30 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 4617d78809671..ce325b5476d74 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-27 +date: 2023-10-30 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 dec1917452ab9..25ad994bf03a3 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-27 +date: 2023-10-30 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 e96f486d76ec3..f359235809433 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-27 +date: 2023-10-30 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 bbbfa50d328fc..0cf21bdd7bdb3 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-27 +date: 2023-10-30 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 5e87f29113d3a..39fbfb46b9fea 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-27 +date: 2023-10-30 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 baa9b59a8a2cf..57d37cf02d8db 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-27 +date: 2023-10-30 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 b0f51908676be..2abb34dbd9d33 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-27 +date: 2023-10-30 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 311ed8901dcd2..c585fcaf9ebc8 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-27 +date: 2023-10-30 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 4a490055b2de0..da4dece580f0c 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-27 +date: 2023-10-30 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 25c56d92ba008..39167e88a89e8 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-27 +date: 2023-10-30 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 09064a8a6374f..91205f6496462 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-27 +date: 2023-10-30 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 16dcf27a0c4f5..21bf5f21c6240 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-27 +date: 2023-10-30 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 6345d81313634..a886df56d3ed7 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-27 +date: 2023-10-30 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 7461f82bb5014..1cb3dec64a254 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-27 +date: 2023-10-30 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 d6013289ae8c6..ca24330a6f448 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-27 +date: 2023-10-30 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 fbfe17d9cc89b..e14ebfea68146 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-27 +date: 2023-10-30 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 f76532f3559de..4fb3bae941fea 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-27 +date: 2023-10-30 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 f5820fbe82c39..443db5c197c5f 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-27 +date: 2023-10-30 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 d884f388dd72c..5c4f2ecdb31c2 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-27 +date: 2023-10-30 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 59362f9862f63..618b23448c813 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-27 +date: 2023-10-30 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 9c8fd2a487b75..2c9f647950f91 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-27 +date: 2023-10-30 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 1fa3fb82ac057..c7391407a995a 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 7dc7e57be1bd8..3c9211babdf90 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-27 +date: 2023-10-30 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 f89f4b292c0d1..5e82a8e7efe25 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-27 +date: 2023-10-30 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 f00dd4134e5b4..1378d3b853465 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-27 +date: 2023-10-30 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 e0cf62abdc083..a4b82ce6fdf0e 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-27 +date: 2023-10-30 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 5900335dbd88f..b3fe73264301f 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-27 +date: 2023-10-30 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 18912fe44db45..eedbc9b47ed80 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-27 +date: 2023-10-30 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 c2db15478e583..b30b6eebe0a69 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-27 +date: 2023-10-30 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 974a67cfab3ab..7df4a8798c804 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-27 +date: 2023-10-30 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 9d9fe0d249fa7..12bb5db177284 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-27 +date: 2023-10-30 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 d2a3afdeb4209..b9c4efd961d63 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-27 +date: 2023-10-30 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 1f379ff7ed48c..bee6a68f793ef 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-27 +date: 2023-10-30 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 9061ef82c9ff2..4c50300935c1e 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-27 +date: 2023-10-30 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 e30c4c28f30b1..f6f2fe9271967 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-27 +date: 2023-10-30 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 76e3d58b1ce77..204b688213c6f 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-27 +date: 2023-10-30 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 cdc7ff71aec45..9b528316672b9 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-27 +date: 2023-10-30 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 8227288933504..6a9e1076d32fb 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-27 +date: 2023-10-30 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 5e140acc8bb0c..d1204e3a219ed 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-27 +date: 2023-10-30 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 a5c8a7e9fa475..2395c626c0183 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 507e4b4564951..d382f0e02bd2d 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-27 +date: 2023-10-30 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 a8a5bb7b0881b..c903d5b38055e 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-27 +date: 2023-10-30 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 c6a7efe20d537..96444f8b1d66d 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-27 +date: 2023-10-30 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 3c8348433de28..afc7ae7db2ef9 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-27 +date: 2023-10-30 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 bda0a77a14272..b54adbfcc61b0 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-27 +date: 2023-10-30 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 41005c89890fe..33f2c2817b6a8 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-27 +date: 2023-10-30 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 849afabb74019..e9599c7a1a012 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-27 +date: 2023-10-30 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 18fe4c3078af5..63b0b5134ecaf 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-27 +date: 2023-10-30 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 a00543c23f1ed..9a5a1d074cc47 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-27 +date: 2023-10-30 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 471459a226934..549add843301e 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-27 +date: 2023-10-30 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 f45f03b4ad6bb..b6c257ef88e5b 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-27 +date: 2023-10-30 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 356fd3518a65a..134fb5d924dbf 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-27 +date: 2023-10-30 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 501ebe50ae3cb..e7b15cb88704b 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-27 +date: 2023-10-30 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 e0098e27bac55..e93edd1f44104 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-27 +date: 2023-10-30 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 cf789962ff455..736b297b679ec 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-27 +date: 2023-10-30 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 ad9ce7d0c8832..dea73cbda9960 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-27 +date: 2023-10-30 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 387883d751a64..b05c23a484e2e 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-27 +date: 2023-10-30 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 2523316b0b590..1dadbee1379e2 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-27 +date: 2023-10-30 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 d75c9e63f493f..155cf5ec169a4 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-27 +date: 2023-10-30 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 63b900ec57b0c..a17bcff7a881d 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-27 +date: 2023-10-30 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 c1f4801e231b0..72264a7807d84 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-27 +date: 2023-10-30 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 ef4866fee2ae2..4d3075bc3b917 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-27 +date: 2023-10-30 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 effc5540f7ade..cf72d2d5f3b9a 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-27 +date: 2023-10-30 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 ed8634a2ca73f..d70b621e4fd2c 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-27 +date: 2023-10-30 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 49f9eb9325b27..b794d4a691a30 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-27 +date: 2023-10-30 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 c15744a35f5fd..59a83917c7d6e 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-27 +date: 2023-10-30 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 8285055837887..72682ce57b708 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-27 +date: 2023-10-30 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 8428620dbc9e3..90a5c76ae7ea6 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-27 +date: 2023-10-30 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 7535328699427..11888dbc6fa93 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-27 +date: 2023-10-30 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 89e52bd940f03..d7db5b670c72b 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-27 +date: 2023-10-30 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 442322144c853..97c3319183cda 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-27 +date: 2023-10-30 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 809dfdbadbe3c..7acc5f126fea5 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-27 +date: 2023-10-30 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 71e0372a0cdb6..b2e455ffdb198 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-27 +date: 2023-10-30 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 3cc13caebcb56..f8a64a33ab199 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-27 +date: 2023-10-30 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 980e06835f478..2c353469c35f7 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-27 +date: 2023-10-30 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 77554d8738050..2707fda6acc16 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-27 +date: 2023-10-30 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 9f7ffeac923dd..3a17fc4a2f058 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-27 +date: 2023-10-30 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 c0aaf84d59907..2820f0fe01cbd 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-27 +date: 2023-10-30 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 723236aec8db4..050fc89e944e8 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-27 +date: 2023-10-30 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 bf673c5155461..285616c1c2efd 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-27 +date: 2023-10-30 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 f223e5c50f29d..3527a80dbd114 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-27 +date: 2023-10-30 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 537c8aa9f4560..b3b1226a6e89c 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-27 +date: 2023-10-30 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 21d3fe5bfc9f9..daba9c306f442 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-27 +date: 2023-10-30 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 b4f8810a769ed..fb9fa16830150 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-27 +date: 2023-10-30 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 54a8b17f6d68b..eb8938c330070 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-27 +date: 2023-10-30 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 ef771a651479f..f8bd416151536 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-27 +date: 2023-10-30 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 3344b588bb447..e736cdf49a49d 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-27 +date: 2023-10-30 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 18c04244fec6e..5549091d9651d 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-27 +date: 2023-10-30 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 5fdf935a5ae38..0e7ed058c5c76 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-27 +date: 2023-10-30 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 4fed8fa030f0d..80ef3d3eee967 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-27 +date: 2023-10-30 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 f87c7a5da9bc7..b392fefa67109 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-27 +date: 2023-10-30 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 79d2b2887337e..2672cba368016 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-27 +date: 2023-10-30 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 2e8e34d2c768e..b828b2a09b19c 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-27 +date: 2023-10-30 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 17317951684a6..77c0fdc059c6a 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-27 +date: 2023-10-30 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 9f9b6a0446ea3..fb4e0cb40c377 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-27 +date: 2023-10-30 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 03d98ba2b390a..da389cad76a1d 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-27 +date: 2023-10-30 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 3c884c87bda73..6418f5ebedf58 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-27 +date: 2023-10-30 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 b48081a95a3d2..8041147ca9a78 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-27 +date: 2023-10-30 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 13e19f2f78951..5fa9af7f05f17 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-27 +date: 2023-10-30 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 4782f8342ba3d..90c3c6cd58410 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-27 +date: 2023-10-30 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 8f24d2c31152b..8a01ca0459d0d 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-27 +date: 2023-10-30 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 3f6d9c22bdd51..5c27396710395 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-27 +date: 2023-10-30 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 6a9ad864f65ee..bf3f64816aeb4 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-27 +date: 2023-10-30 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 59c53cd0af8f1..7fcacfd301f1e 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-27 +date: 2023-10-30 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 d3bfaaf47b6ed..64ce151826faa 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-27 +date: 2023-10-30 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 37ae833c6f4a9..436f3ebda78cc 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-27 +date: 2023-10-30 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 e8e5b751781c1..d563b5962f441 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-27 +date: 2023-10-30 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 91be4d581f527..b3579d359e106 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-27 +date: 2023-10-30 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 b68ac1dacd083..2ef21f3a3f7ca 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-27 +date: 2023-10-30 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 3b8bfae781df5..c8c689a161806 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-27 +date: 2023-10-30 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 1b0241f26d326..979f2b188d95a 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-27 +date: 2023-10-30 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 04a93a7b8e7ac..89a8d4355eefd 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-27 +date: 2023-10-30 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 06e6b98245bb4..71b13ea5e3a15 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-27 +date: 2023-10-30 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 6dbef8a32646e..2f0295694f36e 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-27 +date: 2023-10-30 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 7c73fc7c294d5..3629cb6b190d7 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-27 +date: 2023-10-30 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 172763dcccd96..e71db38b8a8e3 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-27 +date: 2023-10-30 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 00c0270e576b7..5d62230427e88 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-27 +date: 2023-10-30 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 5436cff7575a1..e76bf8845039a 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-27 +date: 2023-10-30 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 c8133ee811a02..49f7e26a3d971 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-27 +date: 2023-10-30 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 b3c96193f7129..a9521624753ca 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-27 +date: 2023-10-30 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 6edb5401fc611..992920a08ef06 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-27 +date: 2023-10-30 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 46aea4c8a9364..a6b718f5da263 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-27 +date: 2023-10-30 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 507dc53782798..5d775bf6ddf55 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-27 +date: 2023-10-30 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 716b6150f4ce7..08238e61a1dc8 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-27 +date: 2023-10-30 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 03fb0a220927a..0a6477bfa8c90 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-27 +date: 2023-10-30 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 c4448a8279754..722d98aee3374 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-27 +date: 2023-10-30 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 cdde0d9d2b4c5..5376f39109123 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-27 +date: 2023-10-30 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 e9e7c3d62381a..51902ab4460cc 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-27 +date: 2023-10-30 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 ed774c363d04a..9e08a1ab2ffa1 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-27 +date: 2023-10-30 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 690e494db2fa4..7517b7d51de4b 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-27 +date: 2023-10-30 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 69f426a2c6317..b6d69f84c7f6b 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-27 +date: 2023-10-30 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 39ce9f1446017..f9096676c2d59 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-27 +date: 2023-10-30 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 ef1191298818c..b5770ac7c24c1 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-27 +date: 2023-10-30 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 08d836257f5d3..20e920545b9b2 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-27 +date: 2023-10-30 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 6ef5b7c2fb045..9623559ad2a78 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-27 +date: 2023-10-30 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 86c682bb2f12d..1c87aee44b48d 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-27 +date: 2023-10-30 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 3fe1c3709da35..56705842e6646 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-27 +date: 2023-10-30 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 ecaeaa879e699..ec2406fc599db 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 dc766c42ad36c..c2d6b5b4b2ed7 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-27 +date: 2023-10-30 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 664b9bf48b59c..59a0ed7e9fe44 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-27 +date: 2023-10-30 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 d958f99d90e93..afabfa0b2eea0 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-27 +date: 2023-10-30 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 d1c40b215a559..70ba23eeaccb5 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-27 +date: 2023-10-30 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 9897d3eaf1908..427cada163c09 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-27 +date: 2023-10-30 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 6304123a323bd..6fd3a667bcb51 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-27 +date: 2023-10-30 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 ce8f1ed7fd3be..61d521cd0a02e 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-27 +date: 2023-10-30 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 7d4b59c889518..11d81ec8f23e9 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-27 +date: 2023-10-30 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 ffa1a41949e97..89a04e0c6a4a4 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 cea7a1ad61cdd..b2b9d0c7d8d20 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-27 +date: 2023-10-30 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 c193dd79f770f..508a062d5eb08 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-27 +date: 2023-10-30 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 7813641bcd01b..a08de81cadd9a 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-27 +date: 2023-10-30 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 118ded94d1723..2048655ca559b 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-27 +date: 2023-10-30 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 d32d17499ea00..9dd5870c03668 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-27 +date: 2023-10-30 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 229c2efa68e86..0583d63bf9f69 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-27 +date: 2023-10-30 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 792fad2cff08e..a7dc3b76dd22e 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-27 +date: 2023-10-30 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 c09f899cce0dd..e8c33d6e41839 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-27 +date: 2023-10-30 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 1b30a34cfd5d2..06c0f8bf05c16 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-27 +date: 2023-10-30 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 d55f9d2374bce..c8cf1c27b7ee1 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-27 +date: 2023-10-30 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 2388a10aa7075..ce9f342666a8d 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-27 +date: 2023-10-30 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 a2d1da16c4a51..0793a924ea10f 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-27 +date: 2023-10-30 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 777b9111b98e3..6fd73eba8ebdd 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-27 +date: 2023-10-30 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 7f053330631e5..3b69b2b968792 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-27 +date: 2023-10-30 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 12b73a9f1faf0..1c402c11066a5 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-27 +date: 2023-10-30 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 0cac397a560e6..9601dbb8a8b65 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-27 +date: 2023-10-30 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 e75e5c8a3a2fd..bccbc8c490913 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-27 +date: 2023-10-30 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 d12a226be5cdd..6ca0dd558de66 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-27 +date: 2023-10-30 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 73f25c26599eb..cd12bc9901548 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-27 +date: 2023-10-30 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 8c9c69f59e989..927b1e3ab44c7 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-27 +date: 2023-10-30 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 af34bcf361fa6..a5dbb1446c314 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-27 +date: 2023-10-30 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 97daa90779144..cca48d854fd5d 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-27 +date: 2023-10-30 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 12701052aa855..819931b34e468 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-27 +date: 2023-10-30 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 29292eeecdcbe..eb072ebfb5f31 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-27 +date: 2023-10-30 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 9a7b1aee7b0cb..ec018e4731a59 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-27 +date: 2023-10-30 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 a0422c91449e8..fabb07c97eed1 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-27 +date: 2023-10-30 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 67226016699e8..cbc576ba09e3f 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-27 +date: 2023-10-30 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 b6af37e21d057..391af24b67ca7 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-27 +date: 2023-10-30 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 6cd523e2c663a..831efcd6324df 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-27 +date: 2023-10-30 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 70d75330aae6d..c8e3309054ca7 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-27 +date: 2023-10-30 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.mdx b/api_docs/kbn_shared_ux_chrome_navigation.mdx index a1b98c37c471b..befe381aad1c2 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-chrome-navigation'] --- import kbnSharedUxChromeNavigationObj from './kbn_shared_ux_chrome_navigation.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_error_boundary.mdx b/api_docs/kbn_shared_ux_error_boundary.mdx index 675bab115373b..8fdf9d4426a09 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', '@kbn/shared-ux-error-boundary'] --- import kbnSharedUxErrorBoundaryObj from './kbn_shared_ux_error_boundary.devdocs.json'; diff --git a/api_docs/kbn_shared_ux_file_context.mdx b/api_docs/kbn_shared_ux_file_context.mdx index 02f4cfee5f262..bd37c8ca34e76 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-27 +date: 2023-10-30 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 7124dbd48cacf..63c1a12e86afd 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-27 +date: 2023-10-30 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 ffd2862078970..b48df2decd67d 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-27 +date: 2023-10-30 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 bdd9cf7aa3931..8d01bb96d124c 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-27 +date: 2023-10-30 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 958ce14ca764e..bb088c846c31b 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-27 +date: 2023-10-30 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 6dab889dff0be..66dfb1d5e4b00 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-27 +date: 2023-10-30 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 e44dbaa149385..745877b81814c 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-27 +date: 2023-10-30 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 b7d72572366c6..5fe095b55b495 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-27 +date: 2023-10-30 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 ef6c4e74e2880..a4d957a0b25ae 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-27 +date: 2023-10-30 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 52cd59eccb53c..1210c6fd604b6 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-27 +date: 2023-10-30 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 622b606406039..e02e58f18b4f4 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-27 +date: 2023-10-30 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 670300fe327fc..b90fed614572c 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-27 +date: 2023-10-30 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 e0acc2b3950f0..e9353f2dd24a0 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-27 +date: 2023-10-30 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 896b69febe703..a900e6114f66b 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-27 +date: 2023-10-30 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 4d23900642832..fe21d2bf61e2d 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-27 +date: 2023-10-30 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 ca138c2d464de..9bf54ec4fadc7 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-27 +date: 2023-10-30 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 ed33f7dfa9082..9c676524971bf 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-27 +date: 2023-10-30 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 f74ee15b09aa8..1194f7ecdf296 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-27 +date: 2023-10-30 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 23192130493e3..343eb78593873 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-27 +date: 2023-10-30 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 ddd10b653f4ca..c96a6e62a4da8 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-27 +date: 2023-10-30 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 1c43fefcdddda..0b22a84bc8f0e 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-27 +date: 2023-10-30 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 300e02ce76df9..e982bbaa135f7 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-27 +date: 2023-10-30 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 1d492d837bbc9..c8d324d955168 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-27 +date: 2023-10-30 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 101eaac304c44..a1abaec5bda2c 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-27 +date: 2023-10-30 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 f9bc2a8c6956c..8807841c8d600 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-27 +date: 2023-10-30 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 02e18d0f211a2..b063e460157d7 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-27 +date: 2023-10-30 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 c11743d605340..ea55f548158b5 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-27 +date: 2023-10-30 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 f9da4bd0bd49b..e8277a8c9e2ac 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-27 +date: 2023-10-30 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 126809cfcd527..57d635bb2845b 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-27 +date: 2023-10-30 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 8cd2f5b9a0a5b..e498fe4e7fdce 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-27 +date: 2023-10-30 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 f1d41a7874166..161d1f968026d 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-27 +date: 2023-10-30 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 ddd1351d88ba0..490418c10fb45 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-27 +date: 2023-10-30 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 35c4fbeef5dbe..6bb2fb8e69c83 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-27 +date: 2023-10-30 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 43b9a1ae22265..7ec05c86724dd 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-27 +date: 2023-10-30 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 ece510ce91f58..91a38f03ef84a 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-27 +date: 2023-10-30 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 051f66f076cd6..312d70c2065fd 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-27 +date: 2023-10-30 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 772befc4870c1..1bbfea5ac9c39 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-27 +date: 2023-10-30 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 a96060f3ae92b..1e3fb9b34fcce 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-27 +date: 2023-10-30 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 8a085cbf6f8ed..012d60d501202 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-27 +date: 2023-10-30 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 ef56c4eff5072..fe8790663a00b 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-27 +date: 2023-10-30 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 8d29731aedd9c..89e6e74124021 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-27 +date: 2023-10-30 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 4aab4d8fae0ef..a464468e979ab 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-27 +date: 2023-10-30 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 4b66b81d867a1..ab3f0c5c1832c 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-27 +date: 2023-10-30 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 092f4a91e330b..50e619e1c6d89 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-27 +date: 2023-10-30 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 d34da4e3f428c..c8ad2f1b6cd52 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-27 +date: 2023-10-30 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 c16c68eeb5079..dceaf901bcbe3 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-27 +date: 2023-10-30 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 ab2e420849409..5442d7582305f 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-27 +date: 2023-10-30 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 47ebff3194b0b..58e901c2b117b 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-27 +date: 2023-10-30 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 17b5c921829a6..c12c416fab5c7 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-27 +date: 2023-10-30 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 6e0716e2481f7..779dbe9a6d22b 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-27 +date: 2023-10-30 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 b185ad610014b..2bffdaf8962df 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-27 +date: 2023-10-30 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 cde6a0452167f..d0040f8f16f68 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-27 +date: 2023-10-30 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 8a38577d396d4..d3340fd3a4f31 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-27 +date: 2023-10-30 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 76c3bd5166667..bac8d99e2a6b2 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-27 +date: 2023-10-30 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 82c2d418f23a0..af60cbce49b80 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-27 +date: 2023-10-30 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 55d4cac7f22b9..f6aac2a7c432b 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-27 +date: 2023-10-30 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 55ce540c509fe..5efe0c61b9d24 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-27 +date: 2023-10-30 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 f2bd7f84d2ac2..0b2135d24a1f4 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-27 +date: 2023-10-30 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 c8d16eff08b2f..41b8a8d0d898b 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-27 +date: 2023-10-30 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 1aaa12df5ed7d..d50a36616b273 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-27 +date: 2023-10-30 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 0000000000000..aea5a227f726a --- /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 0000000000000..fed8544268919 --- /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-30 +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 9cfee77bcb0cf..aba6c0bedbace 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-27 +date: 2023-10-30 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 af6cb685fc071..101f24a3879b1 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-27 +date: 2023-10-30 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 c13639ceec488..cce2d375de80d 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-27 +date: 2023-10-30 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 4255543ddc480..f59fec087ddf1 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-27 +date: 2023-10-30 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 397d445c21feb..d29067d0ae183 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-27 +date: 2023-10-30 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 05142f908bdec..540978c9f8a6f 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-27 +date: 2023-10-30 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 1089b334e48ab..608dad7d5d962 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-27 +date: 2023-10-30 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 f98d228f03c49..db124ab6a3e7d 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-27 +date: 2023-10-30 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 bae76e8189afc..bfd8b450d9130 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-27 +date: 2023-10-30 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 83e0afe173442..67892f59a2fa5 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-27 +date: 2023-10-30 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 6a527f3a21241..494229a1c671a 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-27 +date: 2023-10-30 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 e6078a55207bc..78b5722b67a13 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-27 +date: 2023-10-30 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 d579e7bfc7bac..b9f1a7a5d3054 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-27 +date: 2023-10-30 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 0aff20199bdb6..10c16b80dc619 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-27 +date: 2023-10-30 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 c158a2674010c..3c15fcf3d306a 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-27 +date: 2023-10-30 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 8209fe5ef6518..2c1fe7fcae977 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'metricsDataAccess'] --- import metricsDataAccessObj from './metrics_data_access.devdocs.json'; diff --git a/api_docs/ml.mdx b/api_docs/ml.mdx index 58691429fa494..84badf75ede29 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-27 +date: 2023-10-30 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 8974ca6538236..5fe7b0b11ccca 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-27 +date: 2023-10-30 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 e238f610e591c..98833ef37d55c 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-27 +date: 2023-10-30 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 e67fc0daa5156..06db171e8acbd 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-27 +date: 2023-10-30 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 52055d2c2e6ec..1c0db67bfa768 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-27 +date: 2023-10-30 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 db13f7f5b054c..571600b23feb0 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-27 +date: 2023-10-30 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 7aefbd45cac17..cd9768eef5f70 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-27 +date: 2023-10-30 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 7cbbf9ad683d7..7488d4c103596 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-27 +date: 2023-10-30 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 135796c00424c..cfb4190e6b11d 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-27 +date: 2023-10-30 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 dd44453d89bd9..ca3a06d48b817 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-27 +date: 2023-10-30 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 4ec6701f780ed..c406e2cf10d7e 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-27 +date: 2023-10-30 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 3fe6ed3f373eb..b5495089153d7 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-27 +date: 2023-10-30 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 f74d59eb32fea..919c674decde3 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-27 +date: 2023-10-30 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 e49e1cdc7e664..bf8d936ed17c4 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-27 +date: 2023-10-30 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 4a6c983ebc131..54416c1665fe8 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-27 +date: 2023-10-30 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 | |--------------|----------|-----------------|--------| -| 75915 | 223 | 64916 | 1593 | +| 75925 | 223 | 64928 | 1593 | ## Plugin Directory @@ -63,7 +63,7 @@ tags: ['contributor', 'dev', 'apidocs', 'kibana'] | | [@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 | @@ -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 | @@ -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 66ecd6e21bd4d..6191fedc24ef7 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-27 +date: 2023-10-30 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 b5e7c066027ce..2633348a44ae1 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-27 +date: 2023-10-30 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 c44f5d9549d95..0e1b1fab4bee5 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 355addeeb72ee..8785e5871523d 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-27 +date: 2023-10-30 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 17afbf361eb13..fe89ba29db324 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-27 +date: 2023-10-30 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 1ad42afdd2229..3e1b7579d0e93 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-27 +date: 2023-10-30 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 63131b9bdaac6..c15d47334e506 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-27 +date: 2023-10-30 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 bd30ccc8952ba..2b85c658e4723 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-27 +date: 2023-10-30 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 9b51b43b81b75..c1b648ff330df 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-27 +date: 2023-10-30 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 e70b212fab0f0..268541e0966d6 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-27 +date: 2023-10-30 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 761a96b619dfc..385dc9e63c936 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-27 +date: 2023-10-30 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 97c13d4205a18..31b90df8a40a2 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-27 +date: 2023-10-30 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 d11fff3796721..0728d46946328 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-27 +date: 2023-10-30 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 3aac0f949ccb6..238f1d28701a1 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'savedObjectsTaggingOss'] --- import savedObjectsTaggingOssObj from './saved_objects_tagging_oss.devdocs.json'; diff --git a/api_docs/saved_search.mdx b/api_docs/saved_search.mdx index f6834f38bc271..bbcfb98f32c62 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-27 +date: 2023-10-30 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 336a7b3c449b1..834372b8f0502 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-27 +date: 2023-10-30 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 fd603204c9531..88a076dd089c8 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-27 +date: 2023-10-30 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 62e4a1de07e75..db2edde953605 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-27 +date: 2023-10-30 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 26d3d56375d85..07037769d700a 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-27 +date: 2023-10-30 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 a8e2dce843ae0..be1e74d063c6a 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionEss'] --- import securitySolutionEssObj from './security_solution_ess.devdocs.json'; diff --git a/api_docs/security_solution_serverless.mdx b/api_docs/security_solution_serverless.mdx index a636c726599c7..c7a8198f71e28 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-27 +date: 2023-10-30 tags: ['contributor', 'dev', 'apidocs', 'kibana', 'securitySolutionServerless'] --- import securitySolutionServerlessObj from './security_solution_serverless.devdocs.json'; diff --git a/api_docs/serverless.mdx b/api_docs/serverless.mdx index 8a9874804e4f8..8b0a836b51495 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-27 +date: 2023-10-30 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 d1a42500ea672..c61929c1e149c 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-27 +date: 2023-10-30 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 55127a17fb354..f44f6d1d3df61 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-27 +date: 2023-10-30 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 ee731c3402486..d03db5b15a242 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-27 +date: 2023-10-30 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 bd6a833b0e30d..5ef8fe3c48431 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-27 +date: 2023-10-30 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 dbfa398e44636..96a5a1c58116a 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-27 +date: 2023-10-30 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 3de0462a99949..e8fa7377bd72a 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-27 +date: 2023-10-30 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 fcd06e487ea1c..dcc68892841d7 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-27 +date: 2023-10-30 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 37aa62f795434..2b95b01e47f37 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-27 +date: 2023-10-30 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 d256eb638d94a..26e0852e022be 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-27 +date: 2023-10-30 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 b0d1fe1405989..8f6f3312374c6 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-27 +date: 2023-10-30 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 1204c56061d81..9f5ebb389af34 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-27 +date: 2023-10-30 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 df32d3f900cdb..9f7b5982cd9b7 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-27 +date: 2023-10-30 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 fc442ac16b9be..0b0d50f975413 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-27 +date: 2023-10-30 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 f5b0dd3ebbcc5..577f79ade7245 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-27 +date: 2023-10-30 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 ec4c0aeaa3a1f..d8c1747f35f21 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-27 +date: 2023-10-30 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 a8867a95d8726..b129bdc641d61 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-27 +date: 2023-10-30 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 dc815682f0987..58bb722b4baac 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-27 +date: 2023-10-30 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 8c3ce362ad321..c851d9ebcd877 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-27 +date: 2023-10-30 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 5b12cc1852039..81034eb17e0d9 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-27 +date: 2023-10-30 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 436c86d376ad6..cb6ffa3f99f1c 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-27 +date: 2023-10-30 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 6aab804b6edba..2c6675cadb08d 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-27 +date: 2023-10-30 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 6d1dd462a88a3..345c6337bab00 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-27 +date: 2023-10-30 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 a19ea1e7adfce..2e13dd5ba55c3 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-27 +date: 2023-10-30 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 416987130b349..ccedc018ad5b3 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-27 +date: 2023-10-30 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 7dc0d92e197c8..389885c2f7378 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-27 +date: 2023-10-30 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 2e59abc4e7983..2f68840c6a480 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-27 +date: 2023-10-30 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 9d3029b61f488..f86ec0bc78dce 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-27 +date: 2023-10-30 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 0ddf555eecc28..05bbb5a70a94d 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-27 +date: 2023-10-30 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 33511316ec0bf..f966e9ad1deec 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-27 +date: 2023-10-30 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 e89ac70ca45a7..d3a827d9b5545 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-27 +date: 2023-10-30 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 d4602fa1cb0e1..45e821fe75ef1 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-27 +date: 2023-10-30 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 f3224e3af25fa..d6358f6614f79 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-27 +date: 2023-10-30 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 d20466dd0379f..102e647f89f43 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-27 +date: 2023-10-30 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 6a7dcdbf41ee3..33cb5acc02fa6 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-27 +date: 2023-10-30 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 0cd3cf9e077c1..476026e00b06c 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-27 +date: 2023-10-30 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 33d6017a29908..65036cede03c4 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-27 +date: 2023-10-30 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 7b68154fb87b9..0b11fc1eb8aeb 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-27 +date: 2023-10-30 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 1d75c69af07c7..045b3c97fde29 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-27 +date: 2023-10-30 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 4ce7e646dff5e..1bae179ded182 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-27 +date: 2023-10-30 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 0000000000000..fa21b5a33738e --- /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 0000000000000..4c7d7911ec180 --- /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 0000000000000..e615dd0c0bd1f --- /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 0000000000000..76356b28f7619 --- /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 0000000000000..88a757670736a --- /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 4358c448f3634..7731a65baaac7 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/fleet_packages.json b/fleet_packages.json index 3cdd6bb3a5ea8..4640e150b1a36 100644 --- a/fleet_packages.json +++ b/fleet_packages.json @@ -47,7 +47,7 @@ }, { "name": "profiler_collector", - "version": "8.10.0", + "version": "8.11.0", "forceAlignStackVersion": true }, { @@ -58,4 +58,4 @@ "name": "security_detection_engine", "version": "8.10.3" } -] \ No newline at end of file +] diff --git a/package.json b/package.json index e5213d00d20d4..5f144902b00e2 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 a08f4742bb978..cf16b57c92782 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 8bc9cd6c4115a..706aa478d992b 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 16b58be6c6c03..a5f2bf8677cfd 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 703af63c1027c..c2b90abf24aca 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 1cbdff1883271..4a68281b6ab43 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 0000000000000..be5cc4c893c10 --- /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 a63eca8c9215d..9f31a23492ba7 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 6ac0ce93bec2b..0fc6921d64858 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 3908ff375d0dd..885563451137e 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 e7a56b0c54306..02942c103aef8 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 15fccdf68be4f..bc3cee495a052 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-openapi-generator/kibana.jsonc b/packages/kbn-openapi-generator/kibana.jsonc index b507d94ec022d..d0143b1523e88 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 5847d729d025c..8d72a1a878865 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 1431dafcdfba9..72c6b50d12666 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 0b129b3aa13ed..6bb6fccf7d3b3 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 dbf156b6a7b12..9a5312cf88f53 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 413e8594bd839..88b61320b99f7 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 6162ac1742f69..a2a9bbb134c05 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 d12cef130de2d..0000000000000 --- 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 0000000000000..5ae148c35a7ac --- /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 0000000000000..9bc9cd5cef027 --- /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 0000000000000..1c7537cfb64a1 --- /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 0000000000000..448d08fd5bdfc --- /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 0000000000000..097cc7a314cf9 --- /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 0000000000000..ed8c26135185a --- /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 0000000000000..7a7ebd196097b --- /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 8a3ed6d05600e..06c2b2c18e31a 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 aa4e4ba163681..0000000000000 --- 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 baa45b9c0a93b..0000000000000 --- 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 0000000000000..7cf0d545e2017 --- /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 0000000000000..98c5a08f9b2d8 --- /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 bd0e717d9c76d..0000000000000 --- 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 f2a2e9f63d29b..e0f3388d5f68c 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 2bab91525609b..f11b424694ec1 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 0ec94c4d8ebbf..ad9dff53fdf5e 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 343db1c4a789f..1ff5cb0eafab4 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 ec99f9ba8822b..42362965a7799 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 d7df71b40d71d..df55e012ff7ae 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 26819b76e3e52..963dff502604f 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 3a4386547e1c0..d893a3e1b4ed7 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 9bd4f35cf62a7..c9296a28f35c7 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-zod-helpers/README.md b/packages/kbn-zod-helpers/README.md new file mode 100644 index 0000000000000..5e622edffefe4 --- /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 0000000000000..f1062064dc5cf --- /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 0000000000000..773883b1b364d --- /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 0000000000000..9f7ad63233d33 --- /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 0000000000000..6d27a7e70f859 --- /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 4df4d1fa98104..9e5fcb3fd565c 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 fd7b8cc8ff3f7..4fc4a74047933 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 0000000000000..8f3bd26f692a7 --- /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 0000000000000..d81d52925286b --- /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 0000000000000..b873870f99381 --- /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 0000000000000..0b3850da21158 --- /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 151d9b96185c0..f77c73f390432 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 559bbfb19a415..dc583d97190a9 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 0000000000000..3f5563c189138 --- /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 26cca555e28c5..288f4704d19f8 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 0000000000000..33eaee9f4cbf0 --- /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 3701efac70353..d919488fc744a 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 0000000000000..695fec1f487d7 --- /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 0000000000000..080d6fe0e6ff8 --- /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 d70d553ae05c1..f336096468606 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 2ab485fdb1de1..71ff8ce38636c 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 6252ea3ae6ad8..e3979345f7713 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 aac14c81fe6dc..e3af6faa7985a 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/discover/kibana.jsonc b/src/plugins/discover/kibana.jsonc index 4a46dd14d689f..308e6cda10036 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 f6c87772ec913..f55fdd448df52 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 e1ccf1606d07e..098f789be1a6f 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 774d47d577a6d..bf01e2a7b6669 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 4d5655c012e14..6461603609903 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 86f73e18ca4d0..cf20a679d9568 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 b903d2485bdc4..da82df24e184f 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 d1ff933ecad8f..d8c43fd8dedfe 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 cec9826d00cf7..b6865a10c270b 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 107cbfdb7aa68..a62a797ecfdef 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 d62557654ad6c..b1e9494ce9b56 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 ef2b0a97ba476..02168778c3676 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 8f3b6f91b315b..95d6ad0fcc403 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 54305b7212a55..f586aeaab7630 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 ab096e8337874..72d7f27c7dc48 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 d0bfd585e5080..1050ff72a246c 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 beaa4f8c4e8ce..f6baa4038c230 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 5ec6ce182f55a..83cf114d43b91 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 47c4a6102798e..dfb1b204c4b51 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 8881c30e00e05..fce43bdc4678f 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 b54738514522c..260114bb8b11f 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 613cfec566572..ac8a40d7d580f 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 d5c70be73033a..01d409fc9a1ac 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 e70e8977027ff..aa5feb4dc0b47 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 24b1ba216d054..d57f28b6b71ed 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 596f2a70a13e3..d7af2f06d4b08 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 5d1f4766a775a..d261b4ec2e45d 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 6cf0a0f09de54..e56faa0cc2c1b 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 1effc203084c6..25258a1aff1a4 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 f9aecd4726fb9..16c4dbdc047fb 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 88ecee001dab1..3b7dd8049757a 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 af4eabda5ffc1..091944b660181 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/public/components/renderers/__snapshots__/setup_mode.test.js.snap b/x-pack/plugins/monitoring/public/components/renderers/__snapshots__/setup_mode.test.js.snap index 2e0caa8472fbd..fbc47109d9be5 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 8119685dc65f6..5022e71a348f2 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 322d8a467ef38..e7109f9d6c42d 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 3aa7651320bc3..fc3e0bf71452b 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 965a8b899879a..6970c53e28bf1 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 8d8afe6fb9cca..6ad1d0746a517 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 7db568a07a99e..64d82cabb9437 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 f0df01d87168d..2332f63a54c78 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 d70879bf46d3e..be10c3eaaa5d5 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 bba7a3c014c41..1a83949917690 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 aa1ae58a2b190..104196bababc9 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 3bfb920f25eb1..72d2985cb90e6 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 750e9eab65a96..7f16747f596c2 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 0000000000000..83bd21b1740b8 --- /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 b48a1d9f63a28..0000000000000 --- 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 5ee297ee68791..cbd0f6ee2170c 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 c4978710991ce..5e282e21e4c76 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 c82721780cd0c..4f15624f4c6af 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 24705921bbbf9..adc672c932083 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 af7971b5115d5..7705c70d0d1b4 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 1d99c6346c4c6..3071177cab26e 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 8482620dcb474..07ea07f4ca111 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 ed6cf1dbd4e62..0000000000000 --- 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 01826ac7fa913..5b63b64732da8 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 934c425ed0af9..625423f48ab20 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 ed05677d21dfb..3673e4191e3fc 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 99d81ab771793..d11668e1af6e9 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 062a75f0f1f02..ac7ff7ae7459e 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 0e32989ea8828..a2ad969847da7 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 3dd5d8362a497..3b7237ae8bb71 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 06bfa3e973820..22c507804e1d8 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 8326479db9c14..164f5ee854efc 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 53114d500bc21..c2efee05269c1 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 00d17d55817a5..0d243fc201fb9 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 0aa3f97509f80..0000000000000 --- 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 6738515699814..ccaf290dc5d33 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 0fd840a0c8e71..0000000000000 --- 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 0000000000000..10901049d476d --- /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 0000000000000..6cc6f0c46465c --- /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 335a5f91ffbc5..0000000000000 --- 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 0000000000000..6947953b4d65d --- /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 c77ba322b1c79..0000000000000 --- 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 5ce6fe1bc4727..0d62dfd9c21f3 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 52d59c3a656d6..921f9350550b6 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 b184500990f1c..1b4d506a80648 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 1058c95bfcaac..968199a9459a6 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 765e10fa513bb..abbfa4903ea31 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 19f1a1c44b8bc..1a39d65c1c22f 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 40c01f83ebf4a..e8573502cb662 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 4615a7b0b466f..ff99655a75e89 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 16cc2aec5cf2b..955916b939e82 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 0000000000000..63fa41e047548 --- /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 0000000000000..6b6065ea38220 --- /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 0000000000000..7350dde5e7c2b --- /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 0000000000000..414e51393d972 --- /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 0000000000000..f5b0b751d4452 --- /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 0000000000000..4281cd3121f40 --- /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 0000000000000..a21edeeb6831f --- /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 0000000000000..36581c44e3d35 --- /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 0000000000000..14f2bcf047b5f --- /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 0000000000000..aa0cfd68dc067 --- /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 0000000000000..46a48dae05abf --- /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 0000000000000..4be7e45ba1012 --- /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 9e0035e3e972b..310f96b7bf946 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 07bef679e41ac..6fbe808a0eb48 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 fa3e8e5860116..6d9f39011b675 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 a3d5d56698d9c..f6090383a3ce3 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 0c4071894f99e..e95fa38e0d2e6 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 7e8cb0ebbe58b..9c325d1e70fc0 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 b2206c5a381ef..3b9d0a8fa02c0 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 f0d6638740e32..17ad724039d7e 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 9f82dc5db0605..0000000000000 --- 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 8be56e9d41416..1dcf57d10fb50 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 5edbd070b3972..760b9b7db143a 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 b57882ffdfc5c..b1d7752fb9f89 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 cde6305c91858..299b4a7d7b394 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 b88597a569d89..ac53a3c695d47 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 ddb452a73079e..e3c20db98ab7e 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 994e5908d3933..09067a2e152e1 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 42ef5482b5b5a..feecf23faf293 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 e495ab9647725..cbef9a41de718 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 012c3dbf73149..768626d08769d 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 0000000000000..84124ef5867da --- /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 ca88e7aca4be0..ee02ec47c59b9 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 bf06b41aef39b..40955f2eba40a 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 18f16cfdd3ce2..0000000000000 --- 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 0000000000000..b1b12e0ef1a85 --- /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 cf9ccf0853dcc..85bdb7027447b 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 cdb4085eea1eb..90e5abf36163d 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 0da4acf82f546..0000000000000 --- 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 0000000000000..645e0e77a6de4 --- /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 cbb3b4555a419..eb4ea8a06fc80 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 9e1351c7f25f0..443a3e0862b45 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 c2980211c7fad..0000000000000 --- 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 0000000000000..82095c408fa7e --- /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 56bf7fe2f8d06..5259a677bc1f0 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 46dbbd22b7aaa..86a3a943b6626 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 649898adc9e37..0000000000000 --- 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 0000000000000..b105bd00d94c3 --- /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 b30ac7135c64d..30eedb8859c1f 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 ba6020369f169..d8e3c997e2279 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 0000000000000..ff0832a86f320 --- /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 12b92c026ef00..f3e49fc95a048 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 164c6cfb1a93c..0000000000000 --- 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 0000000000000..b885a8dd64a46 --- /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 c873ceb141770..66236f70b9b6c 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 78a3423182b8d..0000000000000 --- 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 0000000000000..840de35ccf5ca --- /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 7f2645c15e46d..62fba4c321223 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 1883b90c46cbe..98a76e3712b45 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 902b5d0c50899..b70b5a6a7d908 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 01ef956bc4b43..0000000000000 --- 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 3e1a9da5cdc6e..5a60a3331a2ae 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 f27237b563b21..cb34c7fa8ecb5 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 0000000000000..1d10fede9bec4 --- /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 8c5a5accb2c76..8713e295e8f33 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 66d31edf785ac..0000000000000 --- 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 0000000000000..7b53947170798 --- /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 e969cf13ecf27..7adaca37a243b 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 0b695f6c3c021..0000000000000 --- 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 2ec18f7f86c8b..49b56c6673218 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 56fcece0f122a..e868d050ecfe1 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 1b01d913eaee2..d494461d2cdb1 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 a9100970ca753..7fdab0816d650 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 d5ba9b37ae65a..0000000000000 --- 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 2de0116d2875f..0000000000000 --- 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 1d0981df5f411..d0c107abeb726 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 2d32cb801ebd9..dfaa14ba6b7f5 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 0000000000000..235437cc5ed68 --- /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 0000000000000..7e04ef38a0a87 --- /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 41eab285ac3f0..2d2bbccf53108 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 3a15121624b75..0000000000000 --- 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 2357e95dae817..01901971a2a9b 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 7675b21786188..d5ef832547f6a 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 c168cdc837fc3..ae031191fd74d 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 0000000000000..315dc77db6ba8 --- /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 0000000000000..f00529670d58b --- /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 bbe9e9ad5d7e7..a747d2f021b7c 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 9dc071b7ca1ea..742290de8bf43 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 b6d64dbc4d44a..6f0c61834b138 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 cb67964ea7745..dd1ecc4208ef7 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 2dffbc473ecc6..986260c2e463f 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 c1bc91e6ded86..5c4553d7d57af 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 c164068f23709..864b4613857e2 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 f6f406692e50d..c6edaf898f67f 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 ff6e23e68aa63..a2a07209997bf 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 49d06ce33a78b..5750f35d893e2 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 1b3976e91b3c5..0d87a7e0f8755 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/constants.ts b/x-pack/plugins/security_solution/common/endpoint/constants.ts index e4effec5bf4d3..892cb717e1a2c 100644 --- a/x-pack/plugins/security_solution/common/endpoint/constants.ts +++ b/x-pack/plugins/security_solution/common/endpoint/constants.ts @@ -29,14 +29,20 @@ export const metadataIndexPattern = 'metrics-endpoint.metadata-*'; /** index that the metadata transform writes to (destination) and that is used by endpoint APIs */ export const metadataCurrentIndexPattern = 'metrics-endpoint.metadata_current_*'; +// endpoint package V2 has an additional prefix in the transform names +const PACKAGE_V2_PREFIX = 'logs-'; + /** The metadata Transform Name prefix with NO (package) version) */ export const metadataTransformPrefix = 'endpoint.metadata_current-default'; +export const METADATA_CURRENT_TRANSFORM_V2 = `${PACKAGE_V2_PREFIX}${metadataTransformPrefix}`; // metadata transforms pattern for matching all metadata transform ids export const METADATA_TRANSFORMS_PATTERN = 'endpoint.metadata_*'; +export const METADATA_TRANSFORMS_PATTERN_V2 = `${PACKAGE_V2_PREFIX}${METADATA_TRANSFORMS_PATTERN}`; // united metadata transform id export const METADATA_UNITED_TRANSFORM = 'endpoint.metadata_united-default'; +export const METADATA_UNITED_TRANSFORM_V2 = `${PACKAGE_V2_PREFIX}${METADATA_UNITED_TRANSFORM}`; // united metadata transform destination index export const METADATA_UNITED_INDEX = '.metrics-endpoint.metadata_united_default'; diff --git a/x-pack/plugins/security_solution/common/endpoint/index_data.ts b/x-pack/plugins/security_solution/common/endpoint/index_data.ts index 3bbb49cb30707..5caf47b1ade33 100644 --- a/x-pack/plugins/security_solution/common/endpoint/index_data.ts +++ b/x-pack/plugins/security_solution/common/endpoint/index_data.ts @@ -111,8 +111,8 @@ export const indexHostsAndAlerts = usageTracker.track( const shouldWaitForEndpointMetadataDocs = fleet; if (shouldWaitForEndpointMetadataDocs) { - await waitForMetadataTransformsReady(client); - await stopMetadataTransforms(client); + await waitForMetadataTransformsReady(client, epmEndpointPackage.version); + await stopMetadataTransforms(client, epmEndpointPackage.version); } for (let i = 0; i < numHosts; i++) { @@ -147,7 +147,8 @@ export const indexHostsAndAlerts = usageTracker.track( if (shouldWaitForEndpointMetadataDocs) { await startMetadataTransforms( client, - response.agents.map((agent) => agent.agent?.id ?? '') + response.agents.map((agent) => agent.agent?.id ?? ''), + epmEndpointPackage.version ); } 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 0000000000000..926949bf9cd7f --- /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 b689a1d7c20e6..7d402108b9724 100644 --- a/x-pack/plugins/security_solution/common/endpoint/utils/transforms.ts +++ b/x-pack/plugins/security_solution/common/endpoint/utils/transforms.ts @@ -8,25 +8,29 @@ 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, metadataTransformPrefix, + METADATA_CURRENT_TRANSFORM_V2, METADATA_TRANSFORMS_PATTERN, + METADATA_TRANSFORMS_PATTERN_V2, METADATA_UNITED_TRANSFORM, + METADATA_UNITED_TRANSFORM_V2, } from '../constants'; export const waitForMetadataTransformsReady = usageTracker.track( 'waitForMetadataTransformsReady', - async (esClient: Client): Promise => { - await waitFor(() => areMetadataTransformsReady(esClient)); + async (esClient: Client, version: string): Promise => { + await waitFor(() => areMetadataTransformsReady(esClient, version)); } ); export const stopMetadataTransforms = usageTracker.track( 'stopMetadataTransforms', - async (esClient: Client): Promise => { - const transformIds = await getMetadataTransformIds(esClient); + async (esClient: Client, version: string): Promise => { + const transformIds = await getMetadataTransformIds(esClient, version); await Promise.all( transformIds.map((transformId) => @@ -46,14 +50,18 @@ export const startMetadataTransforms = usageTracker.track( async ( esClient: Client, // agentIds to wait for - agentIds: string[] + agentIds: string[], + version: string ): Promise => { - const transformIds = await getMetadataTransformIds(esClient); + const transformIds = await getMetadataTransformIds(esClient, version); + const isV2 = isEndpointPackageV2(version); + const currentTransformPrefix = isV2 ? METADATA_CURRENT_TRANSFORM_V2 : metadataTransformPrefix; const currentTransformId = transformIds.find((transformId) => - transformId.startsWith(metadataTransformPrefix) + transformId.startsWith(currentTransformPrefix) ); + const unitedTransformPrefix = isV2 ? METADATA_UNITED_TRANSFORM_V2 : METADATA_UNITED_TRANSFORM; const unitedTransformId = transformIds.find((transformId) => - transformId.startsWith(METADATA_UNITED_TRANSFORM) + transformId.startsWith(unitedTransformPrefix) ); if (!currentTransformId || !unitedTransformId) { // eslint-disable-next-line no-console @@ -88,22 +96,26 @@ export const startMetadataTransforms = usageTracker.track( ); async function getMetadataTransformStats( - esClient: Client + esClient: Client, + version: string ): Promise { + const transformId = isEndpointPackageV2(version) + ? METADATA_TRANSFORMS_PATTERN_V2 + : METADATA_TRANSFORMS_PATTERN; return ( await esClient.transform.getTransformStats({ - transform_id: METADATA_TRANSFORMS_PATTERN, + transform_id: transformId, allow_no_match: true, }) ).transforms; } -async function getMetadataTransformIds(esClient: Client): Promise { - return (await getMetadataTransformStats(esClient)).map((transform) => transform.id); +async function getMetadataTransformIds(esClient: Client, version: string): Promise { + return (await getMetadataTransformStats(esClient, version)).map((transform) => transform.id); } -async function areMetadataTransformsReady(esClient: Client): Promise { - const transforms = await getMetadataTransformStats(esClient); +async function areMetadataTransformsReady(esClient: Client, version: string): Promise { + const transforms = await getMetadataTransformStats(esClient, version); return !transforms.some( // TODO TransformGetTransformStatsTransformStats type needs to be updated to include health (transform: TransformGetTransformStatsTransformStats & { health?: { status: string } }) => 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 880931ebc0a18..6058f60e1e1c6 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 beeffc98bbe0d..c440248311636 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/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 2b4dbacadac8e..1c73a81b4d26e 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 419385b9d3994..60824648b18e0 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 fb1fdfc1fcc99..0000000000000 --- 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 1dd01aeff817b..876cfb0906563 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 6bce996bc14fc..0582cc13eb92b 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 ee0da0edbfdb9..d7971cce43f80 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 1dc2d4ee29442..cf4446c7fea42 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 9a50076530983..d4108c3eddede 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 112c15969d7fd..c154544f3937c 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 914dbc40be178..2cece43d06f9a 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 dbd11e0c486f3..2a2e7559ee9c9 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 b01fe7209dd1a..080a59a8082f9 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 74b7905a37b17..d5065d6a18308 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 30def4a88c439..4467b18f0b10e 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 0a92a46592dfd..fa9d84f9216bf 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 fbe9c0d46e6b3..2a302a8b0577c 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 c27a195f1324d..a064c19cc8654 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 b37c9d489029f..6cca3e02e3223 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 a42ecbf586440..54c5522d3bb7c 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 91304c44b4e49..cd4f8236eddfb 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 78a788c482654..860e0fc86e850 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 197b97effa1f8..802d5228193e8 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 38293c421bb70..1311fbb19dbef 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 8f3bd6aef95c0..5eedf122a6ac6 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 f223214c3c768..7f1e9cb320306 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 52d8ad920c968..2cc3df6bbb827 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 e4a596f6264bb..8d20758ac7a8d 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 e6d01d1fca588..e18db2201b364 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 3d4501bd1f797..9f8be8c180f94 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 556bd119c5247..5a67b876fe822 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 6e1c53cb2da21..b8aba73818ac3 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 4bb86c26ca760..d44c4effd265f 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 99ee0056b5d21..81438f3708623 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 59196fa5264d6..4df58eb3f70f4 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 7a18a976ab650..f666b6824a76d 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 d525a894a3af4..86c0e7a1dd133 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 870025a9aa5f8..1cdda93858847 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 8b0ff0599dbac..958f8be71fa6b 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 cc975a62be4a0..3525793caa3a3 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 cf195382ec40f..ad3e3f8392eb1 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 a04d8d197da1e..cb20b7910a929 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 b3aa96cfc66fd..0cf89990afc62 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 0f0779c22f949..00de6f0a31c4b 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 4fe7b5378b1ce..58900e1f65a69 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 c0d1db9f837fe..bd5287e04c24b 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 90ba699131625..3fb473204feea 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 9ceff56313f29..38eaeedc44f26 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 517a30df5acf0..b401e2a1fe944 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 4beff423fd1f8..3acccc3352a41 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 0d03c43d3ada5..8b9fb30a4c1ba 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 9b1aac51e3689..56076f54b4817 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 c5e862b3f7a0f..6e4d9221421ee 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 9ea1564b9bcd0..c04dde6b82a45 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.test.ts b/x-pack/plugins/security_solution/server/endpoint/lib/metadata/check_metadata_transforms_task.test.ts index dabd2feed57e2..c5b641853e4db 100644 --- a/x-pack/plugins/security_solution/server/endpoint/lib/metadata/check_metadata_transforms_task.test.ts +++ b/x-pack/plugins/security_solution/server/endpoint/lib/metadata/check_metadata_transforms_task.test.ts @@ -70,6 +70,7 @@ describe('check metadata transforms task', () => { { type: ElasticsearchAssetType.transform } as EsAssetReference, { type: ElasticsearchAssetType.transform } as EsAssetReference, ], + version: '8.11.0', } as Installation); }); 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 ca7a73a272192..d86d8e41fb05a 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 @@ -19,10 +19,14 @@ import type { import { throwUnrecoverableError } from '@kbn/task-manager-plugin/server'; import { ElasticsearchAssetType, FLEET_ENDPOINT_PACKAGE } from '@kbn/fleet-plugin/common'; import type { EndpointAppContext } from '../../types'; -import { METADATA_TRANSFORMS_PATTERN } from '../../../../common/endpoint/constants'; +import { + METADATA_TRANSFORMS_PATTERN, + METADATA_TRANSFORMS_PATTERN_V2, +} from '../../../../common/endpoint/constants'; 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/package_v2'; const SCOPE = ['securitySolution']; const INTERVAL = '2h'; @@ -108,11 +112,21 @@ export class CheckMetadataTransformsTask { const [{ elasticsearch }] = await core.getStartServices(); const esClient = elasticsearch.client.asInternalUser; + const packageClient = this.endpointAppContext.service.getInternalFleetServices().packages; + const installation = await packageClient.getInstallation(FLEET_ENDPOINT_PACKAGE); + if (!installation) { + this.logger.info('no endpoint installation found'); + return { state: taskInstance.state }; + } + + const transformName = isEndpointPackageV2(installation.version) + ? METADATA_TRANSFORMS_PATTERN_V2 + : METADATA_TRANSFORMS_PATTERN; let transformStatsResponse: TransportResult; try { transformStatsResponse = await esClient?.transform.getTransformStats( { - transform_id: METADATA_TRANSFORMS_PATTERN, + transform_id: transformName, }, { meta: true } ); @@ -124,12 +138,6 @@ export class CheckMetadataTransformsTask { return { state: taskInstance.state }; } - const packageClient = this.endpointAppContext.service.getInternalFleetServices().packages; - const installation = await packageClient.getInstallation(FLEET_ENDPOINT_PACKAGE); - if (!installation) { - this.logger.info('no endpoint installation found'); - return { state: taskInstance.state }; - } const expectedTransforms = installation.installed_es.filter( (asset) => asset.type === ElasticsearchAssetType.transform ); 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 9131304d529a3..6641a148d49a1 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 @@ -7,6 +7,8 @@ import type { TypeOf } from '@kbn/config-schema'; import type { Logger, RequestHandler } from '@kbn/core/server'; +import { FLEET_ENDPOINT_PACKAGE } from '@kbn/fleet-plugin/common'; + import type { MetadataListResponse, EndpointSortableField, @@ -25,7 +27,9 @@ import { ENDPOINT_DEFAULT_SORT_DIRECTION, ENDPOINT_DEFAULT_SORT_FIELD, METADATA_TRANSFORMS_PATTERN, + METADATA_TRANSFORMS_PATTERN_V2, } from '../../../../common/endpoint/constants'; +import { isEndpointPackageV2 } from '../../../../common/endpoint/utils/package_v2'; export const getLogger = (endpointAppContext: EndpointAppContext): Logger => { return endpointAppContext.logFactory.get('metadata'); @@ -99,13 +103,21 @@ export const getMetadataRequestHandler = function ( }; export function getMetadataTransformStatsHandler( + endpointAppContext: EndpointAppContext, logger: Logger ): RequestHandler { return async (context, _, response) => { const esClient = (await context.core).elasticsearch.client.asInternalUser; + const packageClient = endpointAppContext.service.getInternalFleetServices().packages; + const installation = await packageClient.getInstallation(FLEET_ENDPOINT_PACKAGE); + const transformName = + installation?.version && !isEndpointPackageV2(installation.version) + ? METADATA_TRANSFORMS_PATTERN + : METADATA_TRANSFORMS_PATTERN_V2; + try { const transformStats = await esClient.transform.getTransformStats({ - transform_id: METADATA_TRANSFORMS_PATTERN, + transform_id: transformName, allow_no_match: true, }); return response.ok({ diff --git a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts index 2f96e8ba82bc9..75d0fb2135fc8 100644 --- a/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts +++ b/x-pack/plugins/security_solution/server/endpoint/routes/metadata/index.ts @@ -103,7 +103,7 @@ export function registerEndpointRoutes( withEndpointAuthz( { all: ['canReadSecuritySolution'] }, logger, - getMetadataTransformStatsHandler(logger) + getMetadataTransformStatsHandler(endpointAppContext, logger) ) ); } 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 a383cc2ad92a9..b0d53f2c43a9d 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 de90b88f6b023..e410146505545 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 6ba2417fc5263..fd69ac51a0f40 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 7960167a993ef..73350b48941db 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 40666a39af4b9..07fb5640eb482 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 eeef7846b519a..59e875a261677 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 ecbf6e47f1825..7ab03f2ac7dcd 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 fb6be3e5e25ea..639f279215801 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 4fdc0d0dedda2..fc3d87d32b432 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 f29c84cf71049..7d7c4a44fa1e1 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 ba9a61d2126e4..98752160fab96 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 13d9f0945f034..dd9fec81f34a6 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 18efcc5c94c2e..5fed0b4e3446a 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 746917a30c298..e9c84c1c50f5c 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 c1479b9ef125d..f45901082d393 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 e50fd79f8cf8a..677556f314239 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 39fdd30306378..5401e2361ca58 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 2bd0cc76e1850..ade1f280c046d 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 6266764018974..e580f5cc11662 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 a281acba9857b..215a0827b015f 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 e01bcd4b7e2ec..d699d5ee7dd55 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 aa9d7c4f8303b..cfbf6a639bb5e 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 90feafaf036fa..c92b37d7710db 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 02ab664602043..d03fe3587ce3b 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 2de991d700e70..b185a91b7ad37 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 569e6f605a6c1..8a9370c64d099 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 eb442f5fc37bb..07b9c9d0cbcd8 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 c42f3f1546be6..1e8931122f5c4 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 84cdc041f9a88..101884b284ebc 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 dfd01f5ad80af..89696e7175a30 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 bbefafb102423..9281c317ab2e0 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 f7e73b49104c1..7003f7f32c062 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 fbebf8374fabf..cf124a3b775d3 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 ffdeba16e3bf2..c457afeb48a92 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 18f752a4a0d97..5672190d3ec00 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 73a9cbe6b93a9..64ed0560f3609 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 50187155e4fdd..1c3907d8109a3 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 33a87c1352359..1fb9527b04b80 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 147314d2640a5..88212b42fe713 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 54bc3d0e5cc47..a336c717224d2 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 ae0a9187922a5..da5b0631cd98b 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 2c5855747636b..4297a24fa8bd3 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 832ade89afa90..c9159c1739c37 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 a6e41257123ab..7775186cde97f 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 3f25ce9922391..59acd2f3422cb 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 163660755a3be..d53281dbf6de1 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 3c59d064d72cc..207917013c7e5 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 cd5faa1ba63e4..bf66ae62855a5 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 c45e49e86db70..e9b98c48d7bad 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 40ae2656e2b26..6f7a1855ac402 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 64259a676189c..8f3ee8f3b903b 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 6170c116d9e63..b4a28335ce132 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 c79e5aec2177a..3fd17335d2ea5 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 aa89829380044..942afb91cfe48 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 528921f1d5bf4..1499734639a33 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 f1eb2607dd25b..e077e37d09835 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 accad22a12817..1c02627eddcd7 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 875e4da8694e1..0000000000000 --- 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 dc529902b730f..0000000000000 --- 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 b235d0b323c8b..0000000000000 --- 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 789761c529e84..0000000000000 --- 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 0000000000000..9e26666ed30d9 --- /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 0000000000000..f0f377ce82d9e --- /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 0000000000000..cd1b0731eedb0 --- /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 0000000000000..8f9f4f76efd89 --- /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 b372c6fd11a7f..7224a6a9e7f5a 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 9e829045013d4..69a1aa79d2410 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 c7aec1dd90d70..4e1f1b4c089e1 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 2969429494b28..2ce7684dedd48 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 0babf1dd3535a..1b2fcee9c7143 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 28c5a92080c93..4e7010a37dd49 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 c30edde0abea8..7c2d88620924f 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 ed87c118bedb9..b5dbf7fca40f2 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 0683868ae3413..1433cb7cac2ff 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 daac0f6c17ddd..9ae0bf9773de6 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 410af1f3f7df3..69425ac7fa4fc 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 0cbff0642aa3c..f643de514c0cb 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 5810830aec3a6..f3ae63dd427aa 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 10967ae7c2ca8..a7c0ba54298fc 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 49d7f9093459b..0000000000000 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 d6c3f1b26a430..0000000000000 --- 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 55bc3aee1d272..0000000000000 --- 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 e833188e6264f..0000000000000 --- 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 2eb539ef4fc78..4f83137df472e 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 bd13e65ed8a25..f9b84469c1eee 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 c2146e8c9dc5f..16ecce357c56b 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 5995b41164aec..ebdf649e1e2bb 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 d362078fc03b1..4562cfc82cfc9 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 0000000000000..635c135e2c8b1 --- /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 d96fbc6beb55b..459b0e656fae0 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 7bd58191bb8c4..97b602c4db617 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 49268f31ed9f9..a3e706c580e5c 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 08d95bc750212..7f49c65ff8a25 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 d6e61120d7dd9..635e402bfc45e 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 f60bf986991ad..dc7cbb4b08dfc 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 909b1bfcf4c5d..97df4c9af323e 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 3ef21fd9a2b2a..1372ffe0139fd 100644 --- a/x-pack/test/security_solution_endpoint/services/endpoint.ts +++ b/x-pack/test/security_solution_endpoint/services/endpoint.ts @@ -12,8 +12,10 @@ import { Client } from '@elastic/elasticsearch'; import { metadataCurrentIndexPattern, metadataTransformPrefix, + METADATA_CURRENT_TRANSFORM_V2, METADATA_UNITED_INDEX, METADATA_UNITED_TRANSFORM, + METADATA_UNITED_TRANSFORM_V2, HOST_METADATA_GET_ROUTE, METADATA_DATASTREAM, } from '@kbn/security-solution-plugin/common/endpoint/constants'; @@ -22,6 +24,8 @@ import { IndexedHostsAndAlertsResponse, 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/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'; @@ -116,11 +120,23 @@ export class EndpointTestResources extends FtrService { customIndexFn, } = options; + let currentTransformName = metadataTransformPrefix; + let unitedTransformName = METADATA_UNITED_TRANSFORM; + if (waitUntilTransformed && customIndexFn) { + const endpointPackage = await getEndpointPackageInfo(this.kbnClient); + const isV2 = isEndpointPackageV2(endpointPackage.version); + + if (isV2) { + currentTransformName = METADATA_CURRENT_TRANSFORM_V2; + unitedTransformName = METADATA_UNITED_TRANSFORM_V2; + } + } + if (waitUntilTransformed && customIndexFn) { // need this before indexing docs so that the united transform doesn't // create a checkpoint with a timestamp after the doc timestamps - await this.stopTransform(metadataTransformPrefix); - await this.stopTransform(METADATA_UNITED_TRANSFORM); + await this.stopTransform(currentTransformName); + await this.stopTransform(unitedTransformName); } // load data into the system @@ -147,10 +163,10 @@ export class EndpointTestResources extends FtrService { ); if (waitUntilTransformed && customIndexFn) { - await this.startTransform(metadataTransformPrefix); + await this.startTransform(currentTransformName); const metadataIds = Array.from(new Set(indexedData.hosts.map((host) => host.agent.id))); await this.waitForEndpoints(metadataIds, waitTimeout); - await this.startTransform(METADATA_UNITED_TRANSFORM); + await this.startTransform(unitedTransformName); } if (waitUntilTransformed) { @@ -342,4 +358,9 @@ export class EndpointTestResources extends FtrService { return response; } + + async isEndpointPackageV2(): Promise { + const endpointPackage = await getEndpointPackageInfo(this.kbnClient); + return isEndpointPackageV2(endpointPackage.version); + } } diff --git a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts index 332bf153524e0..48109e13257ca 100644 --- a/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts +++ b/x-pack/test/security_solution_endpoint_api_int/apis/metadata.ts @@ -16,7 +16,9 @@ import { METADATA_TRANSFORMS_STATUS_ROUTE, METADATA_UNITED_INDEX, METADATA_UNITED_TRANSFORM, + METADATA_UNITED_TRANSFORM_V2, metadataTransformPrefix, + METADATA_CURRENT_TRANSFORM_V2, } from '@kbn/security-solution-plugin/common/endpoint/constants'; import { AGENTS_INDEX } from '@kbn/fleet-plugin/common'; import { indexFleetEndpointPolicy } from '@kbn/security-solution-plugin/common/endpoint/data_loaders/index_fleet_endpoint_policy'; @@ -44,8 +46,7 @@ export default function ({ getService }: FtrProviderContext) { const endpointTestResources = getService('endpointTestResources'); const log = getService('log'); - // FLAKY: https://github.com/elastic/kibana/issues/151854 - describe.skip('test metadata apis', () => { + describe('test metadata apis', () => { describe('list endpoints GET route', () => { const numberOfHostsInFixture = 2; let agent1Timestamp: number; @@ -400,7 +401,17 @@ export default function ({ getService }: FtrProviderContext) { }); describe('get metadata transforms', () => { - const testRegex = /endpoint\.metadata_(united|current)-default-*/; + const testRegex = /(endpoint|logs-endpoint)\.metadata_(united|current)-default-*/; + let currentTransformName = metadataTransformPrefix; + let unitedTransformName = METADATA_UNITED_TRANSFORM; + + before(async () => { + const isPackageV2 = await endpointTestResources.isEndpointPackageV2(); + if (isPackageV2) { + currentTransformName = METADATA_CURRENT_TRANSFORM_V2; + unitedTransformName = METADATA_UNITED_TRANSFORM_V2; + } + }); it('should respond forbidden if no fleet access', async () => { await getService('supertestWithoutAuth') @@ -411,8 +422,8 @@ export default function ({ getService }: FtrProviderContext) { }); it('correctly returns stopped transform stats', async () => { - await stopTransform(getService, `${metadataTransformPrefix}*`); - await stopTransform(getService, `${METADATA_UNITED_TRANSFORM}*`); + await stopTransform(getService, `${currentTransformName}*`); + await stopTransform(getService, `${unitedTransformName}*`); const { body } = await supertest .get(METADATA_TRANSFORMS_STATUS_ROUTE) @@ -428,17 +439,17 @@ export default function ({ getService }: FtrProviderContext) { expect(transforms.length).to.eql(2); const currentTransform = transforms.find((transform) => - transform.id.startsWith(metadataTransformPrefix) + transform.id.startsWith(currentTransformName) ); expect(currentTransform).to.be.ok(); const unitedTransform = transforms.find((transform) => - transform.id.startsWith(METADATA_UNITED_TRANSFORM) + transform.id.startsWith(unitedTransformName) ); expect(unitedTransform).to.be.ok(); - await startTransform(getService, metadataTransformPrefix); - await startTransform(getService, METADATA_UNITED_TRANSFORM); + await startTransform(getService, currentTransformName); + await startTransform(getService, unitedTransformName); }); it('correctly returns started transform stats', async () => { @@ -456,12 +467,12 @@ export default function ({ getService }: FtrProviderContext) { expect(transforms.length).to.eql(2); const currentTransform = transforms.find((transform) => - transform.id.startsWith(metadataTransformPrefix) + transform.id.startsWith(currentTransformName) ); expect(currentTransform).to.be.ok(); const unitedTransform = transforms.find((transform) => - transform.id.startsWith(METADATA_UNITED_TRANSFORM) + transform.id.startsWith(unitedTransformName) ); expect(unitedTransform).to.be.ok(); }); 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 45073d50a1f3d..1885c951b81f1 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 ff24321f11348..a254cb753c864 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 995d17a6dc2c4..124fe461d5306 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 d3899b6d45073..2f277eb084559 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/search/ml/search_bar_features.ts b/x-pack/test_serverless/functional/test_suites/search/ml/search_bar_features.ts index f410b4c1668c6..cdedf3248c191 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 a8571be2daeda..8d48ba2632731 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 21ca495a87eaf..e587356636d61 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 28df3eac7c3f2..af448bc28a07f 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"